[AB-154] split up private and guild message received handler, split handlers into async and sync handlers

adapting the tests and improving tests to reduce usage of MockUtils
adding some util methods to message bean
extending cache for cached messages
enabling to build cached messages from messages in DM channels (they are not part of the message cache)
splitting multiple listeners to different beans, for better overview (emote updated)
adding convenience service for reactions specifically
split cached reaction and cached reactions, singular only contains one user, while the later contains all users
fixing liquibase configuration for assigned role user
fixing assignable role not having a transaction
moved caching update a bit earlier in various methods
fixing bug that a manual unmute caused duplicate unmute notification
fixing short scheduled unmute not checking the new mute state
limiting parameters for roll
This commit is contained in:
Sheldan
2020-12-20 19:21:24 +01:00
parent 69aa82e26e
commit fb3ed69650
200 changed files with 4253 additions and 1813 deletions

View File

@@ -5,10 +5,7 @@ import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService; import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.listener.MessageDeletedListener;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.GuildChannelMember;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -18,13 +15,13 @@ import java.util.Optional;
@Component @Component
@Slf4j @Slf4j
public class AssignablePostDeletedListener implements MessageDeletedListener { public class AssignablePostDeletedListener implements AsyncMessageDeletedListener {
@Autowired @Autowired
private AssignableRolePlacePostManagementService service; private AssignableRolePlacePostManagementService service;
@Override @Override
public void execute(CachedMessage messageBefore, AServerAChannelAUser authorUser, GuildChannelMember authorMember) { public void execute(CachedMessage messageBefore) {
Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(messageBefore.getMessageId()); Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(messageBefore.getMessageId());
messageOptional.ifPresent(post -> { messageOptional.ifPresent(post -> {
AssignableRolePlace assignablePlace = post.getAssignablePlace(); AssignableRolePlace assignablePlace = post.getAssignablePlace();
@@ -39,8 +36,4 @@ public class AssignablePostDeletedListener implements MessageDeletedListener {
return AssignableRoleFeature.ASSIGNABLE_ROLES; return AssignableRoleFeature.ASSIGNABLE_ROLES;
} }
@Override
public Integer getPriority() {
return ListenerPriority.LOW;
}
} }

View File

@@ -12,17 +12,19 @@ import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePl
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService; import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementService; import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementService;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
import dev.sheldan.abstracto.core.listener.ReactedAddedListener; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReaction;
import dev.sheldan.abstracto.core.models.cache.CachedReactions;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.ReactionService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -31,7 +33,7 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j @Slf4j
public class AssignablePostReactionAdded implements ReactedAddedListener { public class AssignablePostReactionAdded implements AsyncReactionAddedListener {
@Autowired @Autowired
private AssignableRolePlacePostManagementService service; private AssignableRolePlacePostManagementService service;
@@ -60,43 +62,49 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
@Autowired @Autowired
private AssignableRoleManagementService assignableRoleManagementService; private AssignableRoleManagementService assignableRoleManagementService;
@Autowired
private ReactionService reactionService;
@Override @Override
public void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent event, AUserInAServer userAdding) { public void executeReactionAdded(CachedMessage message, CachedReactions cachedReaction, ServerUser serverUser) {
Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(message.getMessageId()); Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(message.getMessageId());
if(messageOptional.isPresent()) { if(messageOptional.isPresent()) {
MessageReaction reaction = event.getReaction();
AssignableRolePlacePost assignablePlacePost = messageOptional.get(); AssignableRolePlacePost assignablePlacePost = messageOptional.get();
if(reaction.isSelf()) { if(cachedReaction.getSelf()) {
log.info("Ignoring self reaction on assignable role post in server {}.", message.getServerId()); log.info("Ignoring self reaction on assignable role post in server {}.", message.getServerId());
return; return;
} }
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote(); CachedReaction specificReaction = cachedReaction.getReactionForSpecificUser(serverUser);
Long assignableRolePlaceId = assignablePlacePost.getId();
if(assignablePlacePost.getAssignablePlace().getActive()) { if(assignablePlacePost.getAssignablePlace().getActive()) {
log.info("User {} added reaction to assignable role place {} in server {}. Handling added event.", userAdding.getUserReference().getId(), assignablePlacePost.getId(), event.getGuild().getId()); log.info("User {} added reaction to assignable role place {} in server {}. Handling added event.", serverUser.getUserId(), assignablePlacePost.getId(), serverUser.getServerId());
addAppropriateRoles(event, reaction, assignablePlacePost, reactionEmote, userAdding); addAppropriateRoles(specificReaction, assignablePlacePost, serverUser, message);
} else { } else {
reaction.removeReaction(event.getUser()).submit(); reactionService.removeReactionFromMessage(specificReaction, message).exceptionally(throwable -> {
log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), userAdding.getServerReference().getId()); log.error("Failed to remove reaction on place {} because place is inactive.", assignableRolePlaceId, throwable);
return null;
});
log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), serverUser.getServerId());
} }
} }
} }
private void addAppropriateRoles(GuildMessageReactionAddEvent event, MessageReaction reaction, AssignableRolePlacePost assignablePlacePost, MessageReaction.ReactionEmote reactionEmote, AUserInAServer userAdding) { private void addAppropriateRoles(CachedReaction cachedReaction, AssignableRolePlacePost assignablePlacePost, ServerUser serverUser, CachedMessage message) {
boolean validReaction = false; boolean validReaction = false;
AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace(); AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace();
List<CompletableFuture<Void>> futures = new ArrayList<>(); List<CompletableFuture<Void>> futures = new ArrayList<>();
for (AssignableRole assignableRole : assignablePlacePost.getAssignableRoles()) { for (AssignableRole assignableRole : assignablePlacePost.getAssignableRoles()) {
log.trace("Checking emote {} if it was reaction for assignable role place.", assignableRole.getEmote().getId()); log.trace("Checking emote {} if it was reaction for assignable role place.", assignableRole.getEmote().getId());
if (emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) { if (emoteService.compareCachedEmoteWithAEmote(cachedReaction.getEmote(), assignableRole.getEmote())) {
if(assignableRolePlace.getUniqueRoles()) { if(assignableRolePlace.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles configured. Removing existing reactions and roles.", assignableRolePlace.getId()); log.trace("Assignable role place {} has unique roles configured. Removing existing reactions and roles.", assignableRolePlace.getId());
Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(userAdding); Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(serverUser);
byUserInServer.ifPresent(user -> futures.add(assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, user))); byUserInServer.ifPresent(user -> futures.add(assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, user)));
} }
Long assignableRoleId = assignableRole.getId(); Long assignableRoleId = assignableRole.getId();
log.info("User added {} reaction {} and gets assignable role {} in server {}.", userAdding.getUserReference().getId(), assignableRole.getEmote().getId(), assignableRoleId, userAdding.getServerReference().getId()); log.info("User added {} reaction {} and gets assignable role {} in server {}.", serverUser.getUserId(), assignableRole.getEmote().getId(), assignableRoleId, serverUser.getServerId());
CompletableFuture<Void> roleAdditionFuture = assignableRoleServiceBean.assignAssignableRoleToUser(assignableRoleId, event.getMember()); CompletableFuture<Void> roleAdditionFuture = assignableRoleServiceBean.assignAssignableRoleToUser(assignableRoleId, serverUser);
futures.add(CompletableFuture.allOf(roleAdditionFuture)); futures.add(CompletableFuture.allOf(roleAdditionFuture));
validReaction = true; validReaction = true;
@@ -105,23 +113,23 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
} }
if(!validReaction) { if(!validReaction) {
log.trace("Reaction was not found in the configuration of assignable role place {}, removing reaction.", assignableRolePlace.getId()); log.trace("Reaction was not found in the configuration of assignable role place {}, removing reaction.", assignableRolePlace.getId());
futures.add(reaction.removeReaction(event.getUser()).submit()); futures.add(reactionService.removeReactionFromMessage(cachedReaction, message));
} }
Long assignableRolePlaceId = assignableRolePlace.getId(); Long assignableRolePlaceId = assignableRolePlace.getId();
Long userInServerId = userAdding.getUserInServerId();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid ->
self.updateStoredAssignableRoles(assignableRolePlaceId, userInServerId, reactionEmote) self.updateStoredAssignableRoles(assignableRolePlaceId, serverUser, cachedReaction)
); );
} }
private void updateStoredAssignableRoles(Long assignableRolePlaceId, Long userAdding, MessageReaction.ReactionEmote reactionEmote) { @Transactional
public void updateStoredAssignableRoles(Long assignableRolePlaceId, ServerUser serverUser, CachedReaction cachedReaction) {
AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(assignableRolePlaceId); AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(assignableRolePlaceId);
AUserInAServer userInAServer = userInServerManagementService.loadUser(userAdding); AUserInAServer userInAServer = userInServerManagementService.loadUser(serverUser);
if(place.getUniqueRoles()) { if(place.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles. Deleting all existing references.", assignableRolePlaceId); log.trace("Assignable role place {} has unique roles. Deleting all existing references.", assignableRolePlaceId);
assignableRoleServiceBean.clearAllRolesOfUserInPlace(place, userInAServer); assignableRoleServiceBean.clearAllRolesOfUserInPlace(place, userInAServer);
} }
AssignableRole role = assignableRoleManagementService.getRoleForReactionEmote(reactionEmote, place); AssignableRole role = assignableRoleManagementService.getRoleForReactionEmote(cachedReaction.getEmote(), place);
log.info("Adding role to assignable role {} to user {} in server {}.", role.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId()); log.info("Adding role to assignable role {} to user {} in server {}.", role.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
assignableRoleServiceBean.addRoleToUser(role.getId(), userInAServer); assignableRoleServiceBean.addRoleToUser(role.getId(), userInAServer);
@@ -132,8 +140,4 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
return AssignableRoleFeature.ASSIGNABLE_ROLES; return AssignableRoleFeature.ASSIGNABLE_ROLES;
} }
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
} }

View File

@@ -5,15 +5,13 @@ import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleService; import dev.sheldan.abstracto.assignableroles.service.AssignableRoleService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService; import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionRemovedListener;
import dev.sheldan.abstracto.core.listener.ReactedRemovedListener; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.cache.CachedReactions;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.RoleService; import dev.sheldan.abstracto.core.service.RoleService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -21,7 +19,7 @@ import java.util.Optional;
@Component @Component
@Slf4j @Slf4j
public class AssignablePostReactionRemoved implements ReactedRemovedListener { public class AssignablePostReactionRemoved implements AsyncReactionRemovedListener {
@Autowired @Autowired
private AssignableRolePlacePostManagementService service; private AssignableRolePlacePostManagementService service;
@@ -41,31 +39,26 @@ public class AssignablePostReactionRemoved implements ReactedRemovedListener {
} }
@Override @Override
public void executeReactionRemoved(CachedMessage message, GuildMessageReactionRemoveEvent event, AUserInAServer userRemoving) { public void executeReactionRemoved(CachedMessage message, CachedReactions reactions, ServerUser userRemoving) {
Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(message.getMessageId()); Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(message.getMessageId());
if(messageOptional.isPresent()) { if(messageOptional.isPresent()) {
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote();
AssignableRolePlacePost assignablePlacePost = messageOptional.get(); AssignableRolePlacePost assignablePlacePost = messageOptional.get();
if(assignablePlacePost.getAssignablePlace().getActive()) { if(assignablePlacePost.getAssignablePlace().getActive()) {
assignablePlacePost.getAssignableRoles().forEach(assignableRole -> { assignablePlacePost.getAssignableRoles().forEach(assignableRole -> {
if(emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) { if(emoteService.compareCachedEmoteWithAEmote(reactions.getEmote(), assignableRole.getEmote())) {
Long assignableRoleId = assignableRole.getId(); Long assignableRoleId = assignableRole.getId();
log.info("Removing assignable role {} for user {} in server {} from assignable role place {}.", assignableRoleId, log.info("Removing assignable role {} for user {} in server {} from assignable role place {}.", assignableRoleId,
userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), assignablePlacePost.getAssignablePlace().getId()); userRemoving.getUserId(), userRemoving.getServerId(), assignablePlacePost.getAssignablePlace().getId());
assignableRoleService.fullyRemoveAssignableRoleFromUser(assignableRole, event.getMember()).exceptionally(throwable -> { assignableRoleService.fullyRemoveAssignableRoleFromUser(assignableRole, userRemoving).exceptionally(throwable -> {
log.error("Failed to remove assignable role {} from user {}.", assignableRoleId, event.getMember(), throwable); log.error("Failed to remove assignable role {} from user {} in server {}.", assignableRoleId, userRemoving.getUserId(), userRemoving.getServerId(), throwable);
return null; return null;
}); });
} }
}); });
} else { } else {
log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), userRemoving.getServerReference().getId()); log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), userRemoving.getServerId());
} }
} }
} }
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
} }

View File

@@ -6,6 +6,7 @@ import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRoleManagementServiceBean; import dev.sheldan.abstracto.assignableroles.service.management.AssignableRoleManagementServiceBean;
import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementService; import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementServiceBean; import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementServiceBean;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.RoleService; import dev.sheldan.abstracto.core.service.RoleService;
@@ -50,6 +51,11 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
return roleService.addRoleToMemberFuture(toAdd, role.getRole()); return roleService.addRoleToMemberFuture(toAdd, role.getRole());
} }
@Override
public CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, ServerUser serverUser) {
return botService.retrieveMemberInServer(serverUser).thenCompose(member -> assignAssignableRoleToUser(assignableRoleId, member));
}
@Override @Override
public void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer userInAServer) { public void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer userInAServer) {
AssignedRoleUser user = assignedRoleUserManagementServiceBean.findByUserInServer(userInAServer); AssignedRoleUser user = assignedRoleUserManagementServiceBean.findByUserInServer(userInAServer);
@@ -92,10 +98,11 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
} }
@Override @Override
public CompletableFuture<Void> fullyRemoveAssignableRoleFromUser(AssignableRole assignableRole, Member member) { public CompletableFuture<Void> fullyRemoveAssignableRoleFromUser(AssignableRole assignableRole, ServerUser serverUser) {
Long assignableRoleId = assignableRole.getId(); Long assignableRoleId = assignableRole.getId();
return this.removeAssignableRoleFromUser(assignableRole, member).thenAccept(aVoid -> return botService.retrieveMemberInServer(serverUser).thenCompose(member ->
self.persistRoleRemovalFromUser(assignableRoleId, member) this.removeAssignableRoleFromUser(assignableRole, member)
.thenAccept(aVoid -> self.persistRoleRemovalFromUser(assignableRoleId, member))
); );
} }

View File

@@ -6,6 +6,7 @@ import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.assignableroles.repository.AssignableRoleRepository; import dev.sheldan.abstracto.assignableroles.repository.AssignableRoleRepository;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
@@ -94,4 +95,16 @@ public class AssignableRoleManagementServiceBean implements AssignableRoleManage
} }
throw new AbstractoRunTimeException("Role for reaction was not found."); throw new AbstractoRunTimeException("Role for reaction was not found.");
} }
@Override
public AssignableRole getRoleForReactionEmote(CachedEmote cachedEmote, AssignableRolePlace assignableRolePlace) {
for (AssignableRolePlacePost post : assignableRolePlace.getMessagePosts()) {
for (AssignableRole assignableRole : post.getAssignableRoles()) {
if (emoteService.compareCachedEmoteWithAEmote(cachedEmote, assignableRole.getEmote())) {
return assignableRole;
}
}
}
throw new AbstractoRunTimeException("Role for reaction was not found.");
}
} }

View File

@@ -4,7 +4,9 @@ import dev.sheldan.abstracto.assignableroles.exceptions.AssignedUserNotFoundExce
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser;
import dev.sheldan.abstracto.assignableroles.repository.AssignedRoleUserRepository; import dev.sheldan.abstracto.assignableroles.repository.AssignedRoleUserRepository;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -18,6 +20,9 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Autowired @Autowired
private AssignedRoleUserRepository repository; private AssignedRoleUserRepository repository;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Override @Override
public void addAssignedRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) { public void addAssignedRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) {
Optional<AssignedRoleUser> optional = findByUserInServerOptional(aUserInAServer); Optional<AssignedRoleUser> optional = findByUserInServerOptional(aUserInAServer);
@@ -66,6 +71,12 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
return repository.findById(aUserInAServer.getUserInServerId()); return repository.findById(aUserInAServer.getUserInServerId());
} }
@Override
public Optional<AssignedRoleUser> findByUserInServerOptional(ServerUser serverUser) {
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(serverUser);
return findByUserInServerOptional(aUserInAServer);
}
@Override @Override
public AssignedRoleUser findByUserInServer(AUserInAServer aUserInAServer) { public AssignedRoleUser findByUserInServer(AUserInAServer aUserInAServer) {
return findByUserInServerOptional(aUserInAServer).orElseThrow(() -> new AssignedUserNotFoundException(aUserInAServer)); return findByUserInServerOptional(aUserInAServer).orElseThrow(() -> new AssignedUserNotFoundException(aUserInAServer));

View File

@@ -32,7 +32,7 @@
<addForeignKeyConstraint baseColumnNames="user_id" baseTableName="assigned_role_in_user" constraintName="fk_assigned_role_in_user_assigned_user" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="assigned_role_user" validate="true"/> <addForeignKeyConstraint baseColumnNames="user_id" baseTableName="assigned_role_in_user" constraintName="fk_assigned_role_in_user_assigned_user" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="assigned_role_user" validate="true"/>
</changeSet> </changeSet>
<changeSet author="Sheldan" id="assigned_role_user-fk_assigned_role_user_user"> <changeSet author="Sheldan" id="assigned_role_user-fk_assigned_role_user_user">
<addForeignKeyConstraint baseColumnNames="id" baseTableName="assigned_role_user" constraintName="fk_assigned_role_user_user" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="auser" validate="true"/> <addForeignKeyConstraint baseColumnNames="id" baseTableName="assigned_role_user" constraintName="fk_assigned_role_user_user" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
</changeSet> </changeSet>
</databaseChangeLog> </databaseChangeLog>

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.assignableroles.service;
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
@@ -9,12 +10,13 @@ import java.util.concurrent.CompletableFuture;
public interface AssignableRoleService { public interface AssignableRoleService {
CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member toAdd); CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member toAdd);
CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, ServerUser serverUser);
void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer user); void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer user);
CompletableFuture<Void> fullyAssignAssignableRoleToUser(Long assignableRoleId, Member toAdd); CompletableFuture<Void> fullyAssignAssignableRoleToUser(Long assignableRoleId, Member toAdd);
CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, Member member); CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, Member member);
CompletableFuture<Void> removeAssignableRoleFromUser(Long assignableRoleId, Member member); CompletableFuture<Void> removeAssignableRoleFromUser(Long assignableRoleId, Member member);
CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer); CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer);
CompletableFuture<Void> fullyRemoveAssignableRoleFromUser(AssignableRole assignableRole, Member member); CompletableFuture<Void> fullyRemoveAssignableRoleFromUser(AssignableRole assignableRole, ServerUser serverUser);
void addRoleToUser(Long assignableRoleId, AUserInAServer aUserInAServer); void addRoleToUser(Long assignableRoleId, AUserInAServer aUserInAServer);
void addRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer); void addRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer);
void removeRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer); void removeRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer);

View File

@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.assignableroles.service.management;
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.models.database.ARole;
import net.dv8tion.jda.api.entities.MessageReaction; import net.dv8tion.jda.api.entities.MessageReaction;
@@ -13,4 +14,5 @@ public interface AssignableRoleManagementService {
AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description); AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description);
AssignableRole getByAssignableRoleId(Long assignableRoleId); AssignableRole getByAssignableRoleId(Long assignableRoleId);
AssignableRole getRoleForReactionEmote(MessageReaction.ReactionEmote emote, AssignableRolePlace assignableRolePlace); AssignableRole getRoleForReactionEmote(MessageReaction.ReactionEmote emote, AssignableRolePlace assignableRolePlace);
AssignableRole getRoleForReactionEmote(CachedEmote cachedEmote, AssignableRolePlace assignableRolePlace);
} }

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.assignableroles.service.management;
import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole; import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import java.util.Optional; import java.util.Optional;
@@ -13,5 +14,6 @@ public interface AssignedRoleUserManagementService {
void clearAllAssignedRolesOfUser(AUserInAServer userInAServer); void clearAllAssignedRolesOfUser(AUserInAServer userInAServer);
boolean doesAssignedRoleUserExist(AUserInAServer aUserInAServer); boolean doesAssignedRoleUserExist(AUserInAServer aUserInAServer);
Optional<AssignedRoleUser> findByUserInServerOptional(AUserInAServer aUserInAServer); Optional<AssignedRoleUser> findByUserInServerOptional(AUserInAServer aUserInAServer);
Optional<AssignedRoleUser> findByUserInServerOptional(ServerUser serverUser);
AssignedRoleUser findByUserInServer(AUserInAServer aUserInAServer); AssignedRoleUser findByUserInServer(AUserInAServer aUserInAServer);
} }

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.experience.config; package dev.sheldan.abstracto.experience.config;
import dev.sheldan.abstracto.core.listener.ServerConfigListener; import dev.sheldan.abstracto.core.listener.sync.entity.ServerConfigListener;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService; import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService; import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;

View File

@@ -1,24 +1,24 @@
package dev.sheldan.abstracto.experience.listener; package dev.sheldan.abstracto.experience.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener; import dev.sheldan.abstracto.core.listener.sync.jda.MessageReceivedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.config.features.ExperienceFeature; import dev.sheldan.abstracto.experience.config.features.ExperienceFeature;
import dev.sheldan.abstracto.experience.service.AUserExperienceService; import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import net.dv8tion.jda.api.entities.Message; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/** /**
* This {@link MessageReceivedListener} is responsible to execute the {@link AUserExperienceService} in order to track * This {@link MessageReceivedListener} is responsible to execute the {@link AUserExperienceService} in order to track
* that a certain user has send a message, and experience should be awarded. * that a certain user has send a message, and experience should be awarded.
*/ */
@Component @Component
public class ExperienceTrackerListener implements MessageReceivedListener { @Slf4j
public class ExperienceTrackerListener implements AsyncMessageReceivedListener {
@Autowired @Autowired
private AUserExperienceService userExperienceService; private AUserExperienceService userExperienceService;
@@ -27,9 +27,8 @@ public class ExperienceTrackerListener implements MessageReceivedListener {
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Override @Override
@Transactional(propagation = Propagation.REQUIRES_NEW) public void execute(CachedMessage message) {
public void execute(Message message) { AUserInAServer cause = userInServerManagementService.loadUser(message.getServerId(), message.getAuthor().getAuthorId());
AUserInAServer cause = userInServerManagementService.loadUser(message.getMember());
userExperienceService.addExperience(cause); userExperienceService.addExperience(cause);
} }
@@ -38,8 +37,4 @@ public class ExperienceTrackerListener implements MessageReceivedListener {
return ExperienceFeature.EXPERIENCE; return ExperienceFeature.EXPERIENCE;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -1,15 +1,16 @@
package dev.sheldan.abstracto.experience.listener; package dev.sheldan.abstracto.experience.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncJoinListener;
import dev.sheldan.abstracto.core.listener.JoinListener; import dev.sheldan.abstracto.core.listener.sync.jda.JoinListener;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.config.features.ExperienceFeature; import dev.sheldan.abstracto.experience.config.features.ExperienceFeature;
import dev.sheldan.abstracto.experience.models.database.AUserExperience; import dev.sheldan.abstracto.experience.models.database.AUserExperience;
import dev.sheldan.abstracto.experience.service.AUserExperienceService; import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService; import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -20,7 +21,7 @@ import org.springframework.stereotype.Component;
*/ */
@Component @Component
@Slf4j @Slf4j
public class JoiningUserRoleListener implements JoinListener { public class JoiningUserRoleListener implements AsyncJoinListener {
@Autowired @Autowired
private UserExperienceManagementService userExperienceManagementService; private UserExperienceManagementService userExperienceManagementService;
@@ -28,17 +29,21 @@ public class JoiningUserRoleListener implements JoinListener {
@Autowired @Autowired
private AUserExperienceService userExperienceService; private AUserExperienceService userExperienceService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Override @Override
public void execute(Member member, Guild guild, AUserInAServer aUserInAServer) { public void execute(ServerUser serverUser) {
AUserExperience userExperience = userExperienceManagementService.findUserInServer(aUserInAServer); AUserInAServer userInAServer = userInServerManagementService.loadUser(serverUser.getServerId(), serverUser.getUserId());
Long userInServerId = aUserInAServer.getUserInServerId(); AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer);
Long userInServerId = userInAServer.getUserInServerId();
if(userExperience != null) { if(userExperience != null) {
log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", member.getUser().getIdLong(), guild.getIdLong()); log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", serverUser.getUserId(), serverUser.getServerId());
userExperienceService.syncForSingleUser(userExperience).thenAccept(result -> userExperienceService.syncForSingleUser(userExperience).thenAccept(result ->
log.info("Finished re-assigning experience for re-joning user {} in server {}.", userInServerId, guild.getIdLong()) log.info("Finished re-assigning experience for re-joining user {} in server {}.", userInServerId, serverUser.getServerId())
); );
} else { } else {
log.info("Joined user {} in server {} does not have any previous experience. Not setting up anything.", member.getId(), guild.getId()); log.info("Joined user {} in server {} does not have any previous experience. Not setting up anything.", serverUser.getUserId(), serverUser.getServerId());
} }
} }
@@ -47,8 +52,4 @@ public class JoiningUserRoleListener implements JoinListener {
return ExperienceFeature.EXPERIENCE; return ExperienceFeature.EXPERIENCE;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -34,7 +34,7 @@ public class HasLevelCondition implements SystemCondition {
Long userId = (Long) parameters.get(USER_ID_VARIABLE); Long userId = (Long) parameters.get(USER_ID_VARIABLE);
Integer level = (Integer) parameters.get(LEVEL_VARIABLE); Integer level = (Integer) parameters.get(LEVEL_VARIABLE);
log.info("Evaluating has level condition."); log.info("Evaluating has level condition.");
Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserConditional(userId); Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserOptional(userId);
if(userInServerOptional.isPresent()) { if(userInServerOptional.isPresent()) {
AUserInAServer userInServer = userInServerOptional.get(); AUserInAServer userInServer = userInServerOptional.get();
log.info("Evaluating has level condition for user {} in server {} with level {}.", log.info("Evaluating has level condition for user {} in server {} with level {}.",

View File

@@ -1,13 +1,13 @@
package dev.sheldan.abstracto.experience.listener; package dev.sheldan.abstracto.experience.listener;
import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.ExperienceRelatedTest; import dev.sheldan.abstracto.experience.ExperienceRelatedTest;
import dev.sheldan.abstracto.experience.service.AUserExperienceService; import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
@@ -31,13 +31,13 @@ public class ExperienceTrackerListenerTest extends ExperienceRelatedTest {
@Test @Test
public void testExperienceTracking() { public void testExperienceTracking() {
AServer server = AServer.builder().id(3L).build(); AServer server = Mockito.mock(AServer.class);
AUser user = AUser.builder().id(4L).build(); AUser user = Mockito.mock(AUser.class);
AUserInAServer userInAServer = AUserInAServer.builder().userReference(user).serverReference(server).build(); AUserInAServer userInAServer = Mockito.mock(AUserInAServer.class);
Member member = Mockito.mock(Member.class); CachedMessage mockedMessage = Mockito.mock(CachedMessage.class);
Message mockedMessage = Mockito.mock(Message.class); CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
when(mockedMessage.getMember()).thenReturn(member); when(mockedMessage.getAuthor()).thenReturn(cachedAuthor);
when(userInServerManagementService.loadUser(member)).thenReturn(userInAServer); when(userInServerManagementService.loadUser(server.getId(), user.getId())).thenReturn(userInAServer);
testUnit.execute(mockedMessage); testUnit.execute(mockedMessage);
verify(userExperienceService, times(1)).addExperience(userInAServer); verify(userExperienceService, times(1)).addExperience(userInAServer);
} }

View File

@@ -1,14 +1,13 @@
package dev.sheldan.abstracto.experience.listener; package dev.sheldan.abstracto.experience.listener;
import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.ExperienceRelatedTest; import dev.sheldan.abstracto.experience.ExperienceRelatedTest;
import dev.sheldan.abstracto.experience.models.database.AUserExperience; import dev.sheldan.abstracto.experience.models.database.AUserExperience;
import dev.sheldan.abstracto.experience.service.AUserExperienceService; import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService; import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
import net.dv8tion.jda.api.entities.Guild; import org.junit.Before;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
@@ -32,31 +31,38 @@ public class JoiningUserRoleListenerTest extends ExperienceRelatedTest {
@Mock @Mock
private AUserExperienceService userExperienceService; private AUserExperienceService userExperienceService;
@Mock
private UserInServerManagementService userInServerManagementService;
@Mock
private ServerUser serverUser;
@Mock
private AUserInAServer aUserInAServer;
private static final Long SERVER_ID = 1L;
private static final Long USER_ID = 2L;
@Before
public void setup() {
when(serverUser.getServerId()).thenReturn(SERVER_ID);
when(serverUser.getUserId()).thenReturn(USER_ID);
when(userInServerManagementService.loadUser(SERVER_ID, USER_ID)).thenReturn(aUserInAServer);
}
@Test @Test
public void testUserWithExperienceRejoining() { public void testUserWithExperienceRejoining() {
AUser user = AUser.builder().id(1L).build(); AUserExperience experience = Mockito.mock(AUserExperience.class);
AUserInAServer aUserInAServer = AUserInAServer.builder().userInServerId(2L).userReference(user).build();
Member member = Mockito.mock(Member.class);
User jdaUser = Mockito.mock(User.class);
when(member.getUser()).thenReturn(jdaUser);
when(jdaUser.getIdLong()).thenReturn(user.getId());
Guild guild = Mockito.mock(Guild.class);
AUserExperience experience = AUserExperience.builder().experience(3L).user(aUserInAServer).build();
when(userExperienceManagementService.findUserInServer(aUserInAServer)).thenReturn(experience); when(userExperienceManagementService.findUserInServer(aUserInAServer)).thenReturn(experience);
when(userExperienceService.syncForSingleUser(experience)).thenReturn(CompletableFuture.completedFuture(null)); when(userExperienceService.syncForSingleUser(experience)).thenReturn(CompletableFuture.completedFuture(null));
testUnit.execute(member, guild, aUserInAServer); testUnit.execute(serverUser);
} }
@Test @Test
public void testUserWithOutExperienceRejoining() { public void testUserWithOutExperienceRejoining() {
AUser user = AUser.builder().id(1L).build();
AUserInAServer aUserInAServer = AUserInAServer.builder().userInServerId(2L).userReference(user).build();
Member member = Mockito.mock(Member.class);
Guild guild = Mockito.mock(Guild.class);
AUserExperience experience = AUserExperience.builder().experience(3L).user(aUserInAServer).build();
when(userExperienceManagementService.findUserInServer(aUserInAServer)).thenReturn(null); when(userExperienceManagementService.findUserInServer(aUserInAServer)).thenReturn(null);
testUnit.execute(member, guild, aUserInAServer); testUnit.execute(serverUser);
verify(userExperienceService, times(0)).syncForSingleUser(experience); verify(userExperienceService, times(0)).syncForSingleUser(any());
} }
} }

View File

@@ -1,26 +1,30 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.listener.MessageDeletedListener;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.GuildChannelMember;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.ContextUtils;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures; import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget; import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.utils.ContextUtils;
import dev.sheldan.abstracto.moderation.models.template.listener.MessageDeletedAttachmentLog; import dev.sheldan.abstracto.moderation.models.template.listener.MessageDeletedAttachmentLog;
import dev.sheldan.abstracto.moderation.models.template.listener.MessageDeletedLog; import dev.sheldan.abstracto.moderation.models.template.listener.MessageDeletedLog;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component @Component
@Slf4j @Slf4j
public class MessageDeleteLogListener implements MessageDeletedListener { public class MessageDeleteLogListener implements AsyncMessageDeletedListener {
public static final String MESSAGE_DELETED_TEMPLATE = "message_deleted"; public static final String MESSAGE_DELETED_TEMPLATE = "message_deleted";
public static final String MESSAGE_DELETED_ATTACHMENT_TEMPLATE = "message_deleted_attachment"; public static final String MESSAGE_DELETED_ATTACHMENT_TEMPLATE = "message_deleted_attachment";
@@ -34,36 +38,52 @@ public class MessageDeleteLogListener implements MessageDeletedListener {
@Autowired @Autowired
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Autowired
private BotService botService;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private MessageDeleteLogListener self;
@Override @Override
public void execute(CachedMessage messageFromCache, AServerAChannelAUser authorUser, GuildChannelMember authorMember) { public void execute(CachedMessage messageFromCache) {
botService.getMemberInServerAsync(messageFromCache.getServerId(), messageFromCache.getAuthor().getAuthorId()).thenAccept(member ->
self.executeListener(messageFromCache, member)
);
}
@Transactional
public void executeListener(CachedMessage messageFromCache, Member authorMember) {
log.trace("Message {} in channel {} in guild {} was deleted.", messageFromCache.getMessageId(), messageFromCache.getChannelId(), messageFromCache.getServerId()); log.trace("Message {} in channel {} in guild {} was deleted.", messageFromCache.getMessageId(), messageFromCache.getChannelId(), messageFromCache.getServerId());
TextChannel textChannel = botService.getTextChannelFromServer(messageFromCache.getServerId(), messageFromCache.getChannelId());
MessageDeletedLog logModel = MessageDeletedLog MessageDeletedLog logModel = MessageDeletedLog
.builder() .builder()
.cachedMessage(messageFromCache) .cachedMessage(messageFromCache)
.server(authorUser.getGuild())
.channel(authorUser.getChannel())
.user(authorUser.getUser())
.aUserInAServer(authorUser.getAUserInAServer())
.guild(authorMember.getGuild()) .guild(authorMember.getGuild())
.messageChannel(authorMember.getTextChannel()) .channel(textChannel)
.member(authorMember.getMember()) .member(authorMember)
.build(); .build();
MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_DELETED_TEMPLATE, logModel); MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_DELETED_TEMPLATE, logModel);
postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId()); postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId());
if(messageFromCache.getAttachmentUrls() != null){ if(messageFromCache.getAttachments() != null){
log.trace("Notifying about deletions of {} attachments.", messageFromCache.getAttachmentUrls().size()); log.trace("Notifying about deletions of {} attachments.", messageFromCache.getAttachments().size());
for (int i = 0; i < messageFromCache.getAttachmentUrls().size(); i++) { for (int i = 0; i < messageFromCache.getAttachments().size(); i++) {
MessageDeletedAttachmentLog log = MessageDeletedAttachmentLog MessageDeletedAttachmentLog log = MessageDeletedAttachmentLog
.builder() .builder()
.imageUrl(messageFromCache.getAttachmentUrls().get(i)) .imageUrl(messageFromCache.getAttachments().get(i).getProxyUrl())
.counter(i + 1) .counter(i + 1)
.server(authorUser.getGuild())
.channel(authorUser.getChannel())
.user(authorUser.getUser())
.aUserInAServer(authorUser.getAUserInAServer())
.guild(authorMember.getGuild()) .guild(authorMember.getGuild())
.messageChannel(authorMember.getTextChannel()) .channel(textChannel)
.member(authorMember.getMember()) .member(authorMember)
.build(); .build();
MessageToSend attachmentEmbed = templateService.renderEmbedTemplate(MESSAGE_DELETED_ATTACHMENT_TEMPLATE, log); MessageToSend attachmentEmbed = templateService.renderEmbedTemplate(MESSAGE_DELETED_ATTACHMENT_TEMPLATE, log);
postTargetService.sendEmbedInPostTarget(attachmentEmbed, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId()); postTargetService.sendEmbedInPostTarget(attachmentEmbed, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId());
@@ -76,8 +96,4 @@ public class MessageDeleteLogListener implements MessageDeletedListener {
return ModerationFeatures.LOGGING; return ModerationFeatures.LOGGING;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -1,24 +1,23 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageTextUpdatedListener;
import dev.sheldan.abstracto.core.listener.MessageTextUpdatedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures; import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget; import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.models.template.listener.MessageEditedLog; import dev.sheldan.abstracto.moderation.models.template.listener.MessageEditedLog;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service @Service
@Slf4j @Slf4j
public class MessageEditedListener implements MessageTextUpdatedListener { public class MessageEditedListener implements AsyncMessageTextUpdatedListener {
public static final String MESSAGE_EDITED_TEMPLATE = "message_edited"; public static final String MESSAGE_EDITED_TEMPLATE = "message_edited";
@@ -28,24 +27,33 @@ public class MessageEditedListener implements MessageTextUpdatedListener {
@Autowired @Autowired
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Autowired
private BotService botService;
@Override @Override
@Transactional public void execute(CachedMessage messageBefore, CachedMessage messageAfter) {
public void execute(CachedMessage messageBefore, Message messageAfter) { if(messageBefore.getContent().equals(messageAfter.getContent())) {
if(messageBefore.getContent().equals(messageAfter.getContentRaw())){
log.trace("Message content was the same. Possible reason was: message was not in cache."); log.trace("Message content was the same. Possible reason was: message was not in cache.");
return; return;
} }
log.trace("Message {} in channel {} in guild {} was edited.", messageBefore.getMessageId(), messageBefore.getChannelId(), messageBefore.getServerId()); botService.getMemberInServerAsync(messageAfter.getServerId(), messageAfter.getAuthor().getAuthorId()).thenAccept(author -> {
MessageEditedLog log = MessageEditedLog log.trace("Message {} in channel {} in guild {} was edited.", messageBefore.getMessageId(), messageBefore.getChannelId(), messageBefore.getServerId());
.builder() TextChannel textChannel = botService.getTextChannelFromServer(messageAfter.getServerId(), messageAfter.getChannelId());
.messageAfter(messageAfter) MessageEditedLog log = MessageEditedLog
.messageBefore(messageBefore) .builder()
.messageChannel(messageAfter.getTextChannel()) .messageAfter(messageAfter)
.guild(messageAfter.getGuild()) .messageBefore(messageBefore)
.member(messageAfter.getMember()) .messageChannel(textChannel)
.build(); .guild(textChannel.getGuild())
MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_EDITED_TEMPLATE, log); .member(author)
postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.EDIT_LOG, messageBefore.getServerId()); .build();
MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_EDITED_TEMPLATE, log);
postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.EDIT_LOG, messageBefore.getServerId());
}).exceptionally(throwable -> {
log.error("Failed to load member {} for message edited listener in server {} for message {} in channel {}.",
messageAfter.getAuthor().getAuthorId(), messageAfter.getServerId(), messageAfter.getMessageId(), messageAfter.getChannelId(), throwable);
return null;
});
} }
@Override @Override
@@ -53,8 +61,4 @@ public class MessageEditedListener implements MessageTextUpdatedListener {
return ModerationFeatures.LOGGING; return ModerationFeatures.LOGGING;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -1,13 +1,12 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.listener.ServerConfigListener; import dev.sheldan.abstracto.core.listener.sync.entity.ServerConfigListener;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService; import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService; import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;
import dev.sheldan.abstracto.moderation.config.features.WarningDecayFeature; import dev.sheldan.abstracto.moderation.config.features.WarningDecayFeature;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component

View File

@@ -1,25 +1,25 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener.async;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncJoinListener;
import dev.sheldan.abstracto.core.listener.JoinListener; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.PostTargetService; import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures; import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget; import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap; import java.util.HashMap;
@Service @Service
@Slf4j @Slf4j
public class JoinLogger implements JoinListener { public class JoinLogger implements AsyncJoinListener {
public static final String USER_JOIN_TEMPLATE = "user_join"; public static final String USER_JOIN_TEMPLATE = "user_join";
@@ -29,6 +29,11 @@ public class JoinLogger implements JoinListener {
@Autowired @Autowired
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Autowired
private BotService botService;
@Autowired
private JoinLogger self;
private HashMap<String, Object> getUserParameter(User user) { private HashMap<String, Object> getUserParameter(User user) {
HashMap<String, Object> parameters = new HashMap<>(); HashMap<String, Object> parameters = new HashMap<>();
@@ -37,11 +42,18 @@ public class JoinLogger implements JoinListener {
} }
@Override @Override
public void execute(Member member, Guild guild, AUserInAServer aUserInAServer) { public void execute(ServerUser serverUser) {
log.info("User {} joined server {}.", aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId()); log.info("User {} joined server {}.", serverUser.getUserId(), serverUser.getServerId());
botService.getMemberInServerAsync(serverUser.getServerId(), serverUser.getUserId()).thenAccept(member ->
self.sendJoinLog(serverUser, member)
);
}
@Transactional
public void sendJoinLog(ServerUser serverUser, Member member) {
HashMap<String, Object> parameters = getUserParameter(member.getUser()); HashMap<String, Object> parameters = getUserParameter(member.getUser());
String text = templateService.renderTemplateWithMap(USER_JOIN_TEMPLATE, parameters); String text = templateService.renderTemplateWithMap(USER_JOIN_TEMPLATE, parameters);
postTargetService.sendTextInPostTarget(text, LoggingPostTarget.JOIN_LOG, guild.getIdLong()); postTargetService.sendTextInPostTarget(text, LoggingPostTarget.JOIN_LOG, serverUser.getServerId());
} }
@Override @Override
@@ -49,8 +61,4 @@ public class JoinLogger implements JoinListener {
return ModerationFeatures.LOGGING; return ModerationFeatures.LOGGING;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -1,21 +1,20 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener.async;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncJoinListener;
import dev.sheldan.abstracto.core.listener.JoinListener; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures; import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.service.MuteService; import dev.sheldan.abstracto.moderation.service.MuteService;
import dev.sheldan.abstracto.moderation.service.management.MuteManagementService; import dev.sheldan.abstracto.moderation.service.management.MuteManagementService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Slf4j @Slf4j
public class JoinMuteListener implements JoinListener { public class JoinMuteListener implements AsyncJoinListener {
@Autowired @Autowired
private MuteManagementService muteManagementService; private MuteManagementService muteManagementService;
@@ -23,10 +22,14 @@ public class JoinMuteListener implements JoinListener {
@Autowired @Autowired
private MuteService muteService; private MuteService muteService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Override @Override
public void execute(Member member, Guild guild, AUserInAServer aUserInAServer) { public void execute(ServerUser serverUser) {
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(serverUser.getServerId(), serverUser.getUserId());
if(muteManagementService.hasActiveMute(aUserInAServer)) { if(muteManagementService.hasActiveMute(aUserInAServer)) {
log.info("Re-muting user {} which joined the server {}, because the mute has not ended yet.", member.getIdLong(), guild.getIdLong()); log.info("Re-muting user {} which joined the server {}, because the mute has not ended yet.", serverUser.getUserId(), serverUser.getServerId());
muteService.applyMuteRole(aUserInAServer); muteService.applyMuteRole(aUserInAServer);
} }
} }
@@ -36,8 +39,4 @@ public class JoinMuteListener implements JoinListener {
return ModerationFeatures.MUTING; return ModerationFeatures.MUTING;
} }
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
} }

View File

@@ -1,26 +1,27 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener.async;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncLeaveListener;
import dev.sheldan.abstracto.core.listener.LeaveListener; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.PostTargetService; import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures; import dev.sheldan.abstracto.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget; import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.HashMap; import java.util.HashMap;
@Service @Service
@Slf4j @Slf4j
public class LeaveLogger implements LeaveListener { public class LeaveLogger implements AsyncLeaveListener {
public static final String USER_LEAVE_TEMPLATE = "user_leave"; public static final String USER_LEAVE_TEMPLATE = "user_leave";
@@ -30,6 +31,11 @@ public class LeaveLogger implements LeaveListener {
@Autowired @Autowired
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Autowired
private BotService botService;
@Autowired
private LeaveLogger self;
@NotNull @NotNull
private HashMap<String, Object> getUserParameter(@Nonnull User user) { private HashMap<String, Object> getUserParameter(@Nonnull User user) {
@@ -40,10 +46,17 @@ public class LeaveLogger implements LeaveListener {
} }
@Override @Override
public void execute(Member member, Guild guild) { public void execute(ServerUser serverUser) {
log.info("User {} left server {}.", member.getUser().getId(), guild.getIdLong()); log.info("User {} left server {}.", serverUser.getUserId(), serverUser.getServerId());
botService.getMemberInServerAsync(serverUser.getServerId(), serverUser.getUserId()).thenAccept(member ->
self.executeJoinLogging(serverUser, member)
);
}
@Transactional
public void executeJoinLogging(ServerUser serverUser, Member member) {
String text = templateService.renderTemplateWithMap(USER_LEAVE_TEMPLATE, getUserParameter(member.getUser())); String text = templateService.renderTemplateWithMap(USER_LEAVE_TEMPLATE, getUserParameter(member.getUser()));
postTargetService.sendTextInPostTarget(text, LoggingPostTarget.LEAVE_LOG, guild.getIdLong()); postTargetService.sendTextInPostTarget(text, LoggingPostTarget.LEAVE_LOG, serverUser.getServerId());
} }
@Override @Override
@@ -51,8 +64,4 @@ public class LeaveLogger implements LeaveListener {
return ModerationFeatures.LOGGING; return ModerationFeatures.LOGGING;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -268,15 +268,11 @@ public class MuteServiceBean implements MuteService {
throw new NoMuteFoundException(); throw new NoMuteFoundException();
} }
Mute mute = muteManagementService.getAMuteOf(aUserInAServer); Mute mute = muteManagementService.getAMuteOf(aUserInAServer);
if(Boolean.TRUE.equals(mute.getMuteEnded())) {
log.info("Mute {} has ended already, user {} does not need to be unMuted anymore.", mute.getMuteId().getId(), mute.getMutedUser().getUserReference().getId());
return CompletableFuture.completedFuture(null);
}
Long muteId = mute.getMuteId().getId(); Long muteId = mute.getMuteId().getId();
CompletableFuture<Member> mutingMemberFuture = botService.getMemberInServerAsync(mute.getMutingUser()); CompletableFuture<Member> mutingMemberFuture = botService.getMemberInServerAsync(mute.getMutingUser());
CompletableFuture<Member> mutedMemberFuture = botService.getMemberInServerAsync(mute.getMutedUser()); CompletableFuture<Member> mutedMemberFuture = botService.getMemberInServerAsync(mute.getMutedUser());
Guild guild = botService.getGuildById(mute.getServer().getId()); Guild guild = botService.getGuildById(mute.getMuteId().getServerId());
return endMute(mute).thenCompose(unused -> return endMute(mute, false).thenCompose(unused ->
CompletableFuture.allOf(mutingMemberFuture, mutedMemberFuture) CompletableFuture.allOf(mutingMemberFuture, mutedMemberFuture)
).thenCompose(unused -> self.sendUnMuteLogForManualUnMute(muteId, mutingMemberFuture, mutedMemberFuture, guild)); ).thenCompose(unused -> self.sendUnMuteLogForManualUnMute(muteId, mutingMemberFuture, mutedMemberFuture, guild));
} }
@@ -296,7 +292,11 @@ public class MuteServiceBean implements MuteService {
} }
@Override @Override
public CompletableFuture<Void> endMute(Mute mute) { public CompletableFuture<Void> endMute(Mute mute, Boolean sendNotification) {
if(mute.getMuteEnded()) {
log.info("Mute {} in server {} has already ended. Not unmuting.", mute.getMuteId().getId(), mute.getMuteId().getServerId());
return CompletableFuture.completedFuture(null);
}
Long muteId = mute.getMuteId().getId(); Long muteId = mute.getMuteId().getId();
AServer mutingServer = mute.getServer(); AServer mutingServer = mute.getServer();
log.info("UnMuting {} in server {}", mute.getMutedUser().getUserReference().getId(), mutingServer.getId()); log.info("UnMuting {} in server {}", mute.getMutedUser().getUserReference().getId(), mutingServer.getId());
@@ -315,9 +315,13 @@ public class MuteServiceBean implements MuteService {
CompletableFuture<Member> mutedMemberFuture = botService.getMemberInServerAsync(mute.getMutedUser()); CompletableFuture<Member> mutedMemberFuture = botService.getMemberInServerAsync(mute.getMutedUser());
CompletableFuture<Void> finalFuture = new CompletableFuture<>(); CompletableFuture<Void> finalFuture = new CompletableFuture<>();
CompletableFuture.allOf(mutingMemberFuture, mutedMemberFuture, roleRemovalFuture, mutingMemberFuture, mutedMemberFuture).handle((aVoid, throwable) -> { CompletableFuture.allOf(mutingMemberFuture, mutedMemberFuture, roleRemovalFuture, mutingMemberFuture, mutedMemberFuture).handle((aVoid, throwable) -> {
self.sendUnmuteLog(muteId, guild, mutingMemberFuture, mutedMemberFuture).thenAccept(aVoid1 -> if(sendNotification) {
finalFuture.complete(null) self.sendUnmuteLog(muteId, guild, mutingMemberFuture, mutedMemberFuture).thenAccept(aVoid1 ->
); finalFuture.complete(null)
);
} else {
finalFuture.complete(null);
}
return null; return null;
}); });
@@ -357,7 +361,7 @@ public class MuteServiceBean implements MuteService {
log.info("UnMuting the mute {} in server {}", muteId, serverId); log.info("UnMuting the mute {} in server {}", muteId, serverId);
Optional<Mute> muteOptional = muteManagementService.findMuteOptional(muteId, serverId); Optional<Mute> muteOptional = muteManagementService.findMuteOptional(muteId, serverId);
if(muteOptional.isPresent()) { if(muteOptional.isPresent()) {
return endMute(muteOptional.get()); return endMute(muteOptional.get(), true);
} else { } else {
throw new NoMuteFoundException(); throw new NoMuteFoundException();
} }

View File

@@ -1,20 +1,20 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.PostTargetService; import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget; import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.moderation.listener.async.JoinLogger;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import dev.sheldan.abstracto.core.test.MockUtils;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@@ -29,17 +29,37 @@ public class JoinLoggerTest {
@Mock @Mock
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Mock
private BotService botService;
@Mock
private JoinLogger self;
@Mock
private ServerUser serverUser;
@Mock
private Member member;
private static final Long SERVER_ID = 1L;
private static final Long USER_ID = 2L;
@Test @Test
public void executeListener() { public void testExecute() {
Member joiningMember = Mockito.mock(Member.class); when(serverUser.getUserId()).thenReturn(USER_ID);
Guild guild = Mockito.mock(Guild.class); when(serverUser.getServerId()).thenReturn(SERVER_ID);
Long guildId = 6L; when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(member));
when(guild.getIdLong()).thenReturn(guildId); testUnit.execute(serverUser);
AServer server = MockUtils.getServer(); verify(self, times(1)).sendJoinLog(serverUser, member);
AUserInAServer aUserInAServer = MockUtils.getUserObject(5L, server); }
@Test
public void testJoinLog() {
String message = "text"; String message = "text";
when(serverUser.getServerId()).thenReturn(SERVER_ID);
when(templateService.renderTemplateWithMap(eq(JoinLogger.USER_JOIN_TEMPLATE), any())).thenReturn(message); when(templateService.renderTemplateWithMap(eq(JoinLogger.USER_JOIN_TEMPLATE), any())).thenReturn(message);
testUnit.execute(joiningMember, guild, aUserInAServer); testUnit.sendJoinLog(serverUser, member);
verify(postTargetService, times(1)).sendTextInPostTarget(message, LoggingPostTarget.JOIN_LOG, guildId); verify(postTargetService, times(1)).sendTextInPostTarget(message, LoggingPostTarget.JOIN_LOG, SERVER_ID);
} }
} }

View File

@@ -1,6 +1,9 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.moderation.listener.async.JoinMuteListener;
import dev.sheldan.abstracto.moderation.service.MuteService; import dev.sheldan.abstracto.moderation.service.MuteService;
import dev.sheldan.abstracto.moderation.service.management.MuteManagementService; import dev.sheldan.abstracto.moderation.service.management.MuteManagementService;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
@@ -25,6 +28,9 @@ public class JoinMuteListenerTest {
@Mock @Mock
private MuteService muteService; private MuteService muteService;
@Mock
private UserInServerManagementService userInServerManagementService;
@Mock @Mock
private Member member; private Member member;
@@ -34,17 +40,29 @@ public class JoinMuteListenerTest {
@Mock @Mock
private AUserInAServer joiningUser; private AUserInAServer joiningUser;
@Mock
private ServerUser serverUser;
private static final Long SERVER_ID = 3L;
private static final Long USER_ID = 4L;
@Test @Test
public void testNonMutedUserJoins() { public void testNonMutedUserJoins() {
when(serverUser.getServerId()).thenReturn(SERVER_ID);
when(serverUser.getUserId()).thenReturn(USER_ID);
when(userInServerManagementService.loadUser(SERVER_ID, USER_ID)).thenReturn(joiningUser);
when(muteManagementService.hasActiveMute(joiningUser)).thenReturn(false); when(muteManagementService.hasActiveMute(joiningUser)).thenReturn(false);
testUnit.execute(member, guild, joiningUser); testUnit.execute(serverUser);
verify(muteService, times(0)).applyMuteRole(joiningUser); verify(muteService, times(0)).applyMuteRole(joiningUser);
} }
@Test @Test
public void testMutedUserJoins() { public void testMutedUserJoins() {
when(serverUser.getServerId()).thenReturn(SERVER_ID);
when(serverUser.getUserId()).thenReturn(USER_ID);
when(userInServerManagementService.loadUser(SERVER_ID, USER_ID)).thenReturn(joiningUser);
when(muteManagementService.hasActiveMute(joiningUser)).thenReturn(true); when(muteManagementService.hasActiveMute(joiningUser)).thenReturn(true);
testUnit.execute(member, guild, joiningUser); testUnit.execute(serverUser);
verify(muteService, times(1)).applyMuteRole(joiningUser); verify(muteService, times(1)).applyMuteRole(joiningUser);
} }
} }

View File

@@ -1,9 +1,11 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.PostTargetService; import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget; import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.moderation.listener.async.LeaveLogger;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import org.junit.Test; import org.junit.Test;
@@ -13,6 +15,8 @@ import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@@ -27,18 +31,39 @@ public class LeaveLoggerTest {
@Mock @Mock
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Mock
private BotService botService;
@Mock
private LeaveLogger self;
@Mock
private ServerUser leavingUser;
@Mock
private Member member;
private static final Long SERVER_ID = 1L;
private static final Long USER_ID = 2L;
@Test
public void testExecute() {
when(leavingUser.getUserId()).thenReturn(USER_ID);
when(leavingUser.getServerId()).thenReturn(SERVER_ID);
when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(member));
testUnit.execute(leavingUser);
verify(self, times(1)).executeJoinLogging(leavingUser, member);
}
@Test @Test
public void executeListener() { public void executeListener() {
Member leavingMember = Mockito.mock(Member.class);
Guild guild = Mockito.mock(Guild.class);
User user = Mockito.mock(User.class); User user = Mockito.mock(User.class);
when(leavingMember.getUser()).thenReturn(user); when(member.getUser()).thenReturn(user);
Long guildId = 6L;
when(guild.getIdLong()).thenReturn(guildId);
String message = "text"; String message = "text";
when(leavingUser.getServerId()).thenReturn(SERVER_ID);
when(templateService.renderTemplateWithMap(eq(LeaveLogger.USER_LEAVE_TEMPLATE), any())).thenReturn(message); when(templateService.renderTemplateWithMap(eq(LeaveLogger.USER_LEAVE_TEMPLATE), any())).thenReturn(message);
testUnit.execute(leavingMember, guild); testUnit.executeJoinLogging(leavingUser, member);
verify(postTargetService, times(1)).sendTextInPostTarget(message, LoggingPostTarget.LEAVE_LOG, guildId); verify(postTargetService, times(1)).sendTextInPostTarget(message, LoggingPostTarget.LEAVE_LOG, SERVER_ID);
} }
} }

View File

@@ -1,24 +1,22 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser; import dev.sheldan.abstracto.core.models.cache.CachedAttachment;
import dev.sheldan.abstracto.core.models.GuildChannelMember; import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.PostTargetService; import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.utils.ContextUtils; import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget; import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.moderation.models.template.listener.MessageDeletedAttachmentLog; import dev.sheldan.abstracto.moderation.models.template.listener.MessageDeletedAttachmentLog;
import dev.sheldan.abstracto.moderation.models.template.listener.MessageDeletedLog; import dev.sheldan.abstracto.moderation.models.template.listener.MessageDeletedLog;
import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import dev.sheldan.abstracto.core.test.MockUtils;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.TextChannel;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.*; import org.mockito.*;
@@ -26,6 +24,7 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@@ -34,17 +33,26 @@ public class MessageDeleteLogListenerTest {
@InjectMocks @InjectMocks
private MessageDeleteLogListener testUnit; private MessageDeleteLogListener testUnit;
@Mock
private ContextUtils contextUtils;
@Mock @Mock
private TemplateService templateService; private TemplateService templateService;
@Mock @Mock
private PostTargetService postTargetService; private PostTargetService postTargetService;
private AServerAChannelAUser authorUser; @Mock
private GuildChannelMember authorMember; private BotService botService;
@Mock
private ChannelManagementService channelManagementService;
@Mock
private ServerManagementService serverManagementService;
@Mock
private UserInServerManagementService userInServerManagementService;
@Mock
private MessageDeleteLogListener self;
@Captor @Captor
private ArgumentCaptor<MessageDeletedLog> captor; private ArgumentCaptor<MessageDeletedLog> captor;
@@ -55,46 +63,69 @@ public class MessageDeleteLogListenerTest {
@Captor @Captor
private ArgumentCaptor<MessageToSend> messageCaptor; private ArgumentCaptor<MessageToSend> messageCaptor;
@Before private static final Long SERVER_ID = 1L;
public void setup() { private static final Long AUTHOR_ID = 2L;
AServer server = MockUtils.getServer(); private static final Long CHANNEL_ID = 3L;
AUserInAServer aUserInAServer = MockUtils.getUserObject(4L, server);
AChannel channel = MockUtils.getTextChannel(server, 5L); @Mock
authorUser = AServerAChannelAUser.builder().guild(server).channel(channel).aUserInAServer(aUserInAServer).build(); private CachedMessage deletedMessage;
Member member = Mockito.mock(Member.class);
Guild guild = Mockito.mock(Guild.class); @Mock
TextChannel textChannel = Mockito.mock(TextChannel.class); private CachedAuthor cachedAuthor;
authorMember = GuildChannelMember.builder().guild(guild).textChannel(textChannel).member(member).build();
@Mock
private TextChannel textChannel;
@Mock
private Member member;
@Mock
private Guild guild;
@Test
public void testExecuteListener() {
when(deletedMessage.getAuthor()).thenReturn(cachedAuthor);
when(cachedAuthor.getAuthorId()).thenReturn(AUTHOR_ID);
when(deletedMessage.getServerId()).thenReturn(SERVER_ID);
when(botService.getMemberInServerAsync(SERVER_ID, AUTHOR_ID)).thenReturn(CompletableFuture.completedFuture(member));
testUnit.execute(deletedMessage);
verify(self, times(1)).executeListener(deletedMessage, member);
} }
@Test @Test
public void testExecuteListenerWithSimpleMessage() { public void testExecuteListenerWithSimpleMessage() {
CachedMessage message = CachedMessage.builder().serverId(authorUser.getGuild().getId()).build(); when(deletedMessage.getServerId()).thenReturn(SERVER_ID);
when(deletedMessage.getChannelId()).thenReturn(CHANNEL_ID);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class); MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(member.getGuild()).thenReturn(guild);
when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_TEMPLATE), captor.capture())).thenReturn(messageToSend); when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_TEMPLATE), captor.capture())).thenReturn(messageToSend);
testUnit.execute(message, authorUser, authorMember); when(botService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel);
verify(postTargetService, times(1)).sendEmbedInPostTarget(messageToSend, LoggingPostTarget.DELETE_LOG, authorUser.getGuild().getId()); testUnit.executeListener(deletedMessage, member);
verify(postTargetService, times(1)).sendEmbedInPostTarget(messageToSend, LoggingPostTarget.DELETE_LOG, SERVER_ID);
MessageDeletedLog messageDeletedLog = captor.getValue(); MessageDeletedLog messageDeletedLog = captor.getValue();
Assert.assertEquals(message, messageDeletedLog.getCachedMessage()); Assert.assertEquals(deletedMessage, messageDeletedLog.getCachedMessage());
Assert.assertEquals(authorUser.getGuild(), messageDeletedLog.getServer()); Assert.assertEquals(guild, messageDeletedLog.getGuild());
Assert.assertEquals(authorUser.getChannel(), messageDeletedLog.getChannel()); Assert.assertEquals(textChannel, messageDeletedLog.getChannel());
Assert.assertEquals(authorUser.getUser(), messageDeletedLog.getUser()); Assert.assertEquals(member, messageDeletedLog.getMember());
Assert.assertEquals(authorUser.getAUserInAServer(), messageDeletedLog.getAUserInAServer());
Assert.assertEquals(authorMember.getGuild(), messageDeletedLog.getGuild());
Assert.assertEquals(authorMember.getTextChannel(), messageDeletedLog.getMessageChannel());
Assert.assertEquals(authorMember.getMember(), messageDeletedLog.getMember());
} }
@Test @Test
public void testExecuteListenerWithOneAttachment() { public void testExecuteListenerWithOneAttachment() {
String attachmentUrl = "url"; String attachmentUrl = "url";
CachedMessage message = CachedMessage.builder().serverId(authorUser.getGuild().getId()).attachmentUrls(Arrays.asList(attachmentUrl)).build(); when(deletedMessage.getServerId()).thenReturn(SERVER_ID);
when(deletedMessage.getChannelId()).thenReturn(CHANNEL_ID);
when(botService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel);
CachedAttachment cachedAttachment = Mockito.mock(CachedAttachment.class);
when(cachedAttachment.getProxyUrl()).thenReturn(attachmentUrl);
List<CachedAttachment> attachmentList = Arrays.asList(cachedAttachment);
when(deletedMessage.getAttachments()).thenReturn(attachmentList);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class); MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
MessageToSend attachmentMessage = Mockito.mock(MessageToSend.class); MessageToSend attachmentMessage = Mockito.mock(MessageToSend.class);
when(member.getGuild()).thenReturn(guild);
when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_TEMPLATE), captor.capture())).thenReturn(messageToSend); when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_TEMPLATE), captor.capture())).thenReturn(messageToSend);
when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_ATTACHMENT_TEMPLATE), attachmentCaptor.capture())).thenReturn(attachmentMessage); when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_ATTACHMENT_TEMPLATE), attachmentCaptor.capture())).thenReturn(attachmentMessage);
testUnit.execute(message, authorUser, authorMember); testUnit.executeListener(deletedMessage, member);
verify(postTargetService, times(2)).sendEmbedInPostTarget(messageCaptor.capture(), eq(LoggingPostTarget.DELETE_LOG), eq(authorUser.getGuild().getId())); verify(postTargetService, times(2)).sendEmbedInPostTarget(messageCaptor.capture(), eq(LoggingPostTarget.DELETE_LOG), eq(SERVER_ID));
List<MessageToSend> messagesSent = messageCaptor.getAllValues(); List<MessageToSend> messagesSent = messageCaptor.getAllValues();
Assert.assertEquals(messageToSend, messagesSent.get(0)); Assert.assertEquals(messageToSend, messagesSent.get(0));
Assert.assertEquals(attachmentMessage, messagesSent.get(1)); Assert.assertEquals(attachmentMessage, messagesSent.get(1));
@@ -105,15 +136,24 @@ public class MessageDeleteLogListenerTest {
@Test @Test
public void testExecuteListenerWithTwoAttachment() { public void testExecuteListenerWithTwoAttachment() {
when(deletedMessage.getServerId()).thenReturn(SERVER_ID);
when(deletedMessage.getChannelId()).thenReturn(CHANNEL_ID);
when(botService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel);
String attachmentUrl = "url"; String attachmentUrl = "url";
String secondAttachmentUrl = "url2"; String secondAttachmentUrl = "url2";
CachedMessage message = CachedMessage.builder().serverId(authorUser.getGuild().getId()).attachmentUrls(Arrays.asList(attachmentUrl, secondAttachmentUrl)).build(); CachedAttachment cachedAttachment = Mockito.mock(CachedAttachment.class);
when(cachedAttachment.getProxyUrl()).thenReturn(attachmentUrl);
CachedAttachment secondCachedAttachment = Mockito.mock(CachedAttachment.class);
when(secondCachedAttachment.getProxyUrl()).thenReturn(secondAttachmentUrl);
List<CachedAttachment> cachedAttachments = Arrays.asList(cachedAttachment, secondCachedAttachment);
when(deletedMessage.getAttachments()).thenReturn(cachedAttachments);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class); MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(member.getGuild()).thenReturn(guild);
MessageToSend attachmentMessage = Mockito.mock(MessageToSend.class); MessageToSend attachmentMessage = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_TEMPLATE), captor.capture())).thenReturn(messageToSend); when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_TEMPLATE), captor.capture())).thenReturn(messageToSend);
when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_ATTACHMENT_TEMPLATE), attachmentCaptor.capture())).thenReturn(attachmentMessage); when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_ATTACHMENT_TEMPLATE), attachmentCaptor.capture())).thenReturn(attachmentMessage);
testUnit.execute(message, authorUser, authorMember); testUnit.executeListener(deletedMessage, member);
verify(postTargetService, times(3)).sendEmbedInPostTarget(messageCaptor.capture(), eq(LoggingPostTarget.DELETE_LOG), eq(authorUser.getGuild().getId())); verify(postTargetService, times(3)).sendEmbedInPostTarget(messageCaptor.capture(), eq(LoggingPostTarget.DELETE_LOG), eq(SERVER_ID));
List<MessageToSend> messagesSent = messageCaptor.getAllValues(); List<MessageToSend> messagesSent = messageCaptor.getAllValues();
Assert.assertEquals(messageToSend, messagesSent.get(0)); Assert.assertEquals(messageToSend, messagesSent.get(0));
Assert.assertEquals(attachmentMessage, messagesSent.get(1)); Assert.assertEquals(attachmentMessage, messagesSent.get(1));
@@ -125,25 +165,17 @@ public class MessageDeleteLogListenerTest {
private void verifyMessageDeletedLog() { private void verifyMessageDeletedLog() {
MessageDeletedLog messageDeletedLog = captor.getValue(); MessageDeletedLog messageDeletedLog = captor.getValue();
Assert.assertEquals(authorUser.getGuild(), messageDeletedLog.getServer()); Assert.assertEquals(guild, messageDeletedLog.getGuild());
Assert.assertEquals(authorUser.getChannel(), messageDeletedLog.getChannel()); Assert.assertEquals(textChannel, messageDeletedLog.getChannel());
Assert.assertEquals(authorUser.getUser(), messageDeletedLog.getUser()); Assert.assertEquals(member, messageDeletedLog.getMember());
Assert.assertEquals(authorUser.getAUserInAServer(), messageDeletedLog.getAUserInAServer());
Assert.assertEquals(authorMember.getGuild(), messageDeletedLog.getGuild());
Assert.assertEquals(authorMember.getTextChannel(), messageDeletedLog.getMessageChannel());
Assert.assertEquals(authorMember.getMember(), messageDeletedLog.getMember());
} }
private void verifyAttachmentLog(String attachmentUrl, MessageDeletedAttachmentLog attachmentLog, Integer index) { private void verifyAttachmentLog(String attachmentUrl, MessageDeletedAttachmentLog attachmentLog, Integer index) {
Assert.assertEquals(attachmentUrl, attachmentLog.getImageUrl()); Assert.assertEquals(attachmentUrl, attachmentLog.getImageUrl());
Assert.assertEquals(index, attachmentLog.getCounter()); Assert.assertEquals(index, attachmentLog.getCounter());
Assert.assertEquals(authorUser.getGuild(), attachmentLog.getServer()); Assert.assertEquals(guild, attachmentLog.getGuild());
Assert.assertEquals(authorUser.getChannel(), attachmentLog.getChannel()); Assert.assertEquals(textChannel, attachmentLog.getChannel());
Assert.assertEquals(authorUser.getUser(), attachmentLog.getUser()); Assert.assertEquals(member, attachmentLog.getMember());
Assert.assertEquals(authorUser.getAUserInAServer(), attachmentLog.getAUserInAServer());
Assert.assertEquals(authorMember.getGuild(), attachmentLog.getGuild());
Assert.assertEquals(authorMember.getTextChannel(), attachmentLog.getMessageChannel());
Assert.assertEquals(authorMember.getMember(), attachmentLog.getMember());
} }

View File

@@ -1,6 +1,8 @@
package dev.sheldan.abstracto.moderation.listener; package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.PostTargetService; import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget; import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.moderation.models.template.listener.MessageEditedLog; import dev.sheldan.abstracto.moderation.models.template.listener.MessageEditedLog;
@@ -8,7 +10,6 @@ import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.TextChannel;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@@ -19,6 +20,8 @@ import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@@ -34,15 +37,22 @@ public class MessageEditedListenerTest {
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Mock @Mock
private Message messageAfter; private BotService botService;
@Mock
private CachedMessage messageAfter;
@Mock @Mock
private CachedMessage messageBefore; private CachedMessage messageBefore;
private static final Long SERVER_ID = 4L;
private static final Long CHANNEL_ID = 5L;
private static final Long AUTHOR_ID = 6L;
@Test @Test
public void testExecuteListenerWithSameContent() { public void testExecuteListenerWithSameContent() {
String content = "text"; String content = "text";
when(messageAfter.getContentRaw()).thenReturn(content); when(messageAfter.getContent()).thenReturn(content);
when(messageBefore.getContent()).thenReturn(content); when(messageBefore.getContent()).thenReturn(content);
testUnit.execute(messageBefore, messageAfter); testUnit.execute(messageBefore, messageAfter);
verify(templateService, times(0)).renderEmbedTemplate(eq(MessageEditedListener.MESSAGE_EDITED_TEMPLATE), any()); verify(templateService, times(0)).renderEmbedTemplate(eq(MessageEditedListener.MESSAGE_EDITED_TEMPLATE), any());
@@ -53,25 +63,29 @@ public class MessageEditedListenerTest {
String content = "text"; String content = "text";
String contentAfterwards = "text2"; String contentAfterwards = "text2";
TextChannel channel = Mockito.mock(TextChannel.class); TextChannel channel = Mockito.mock(TextChannel.class);
Long serverId = 5L; when(messageAfter.getContent()).thenReturn(contentAfterwards);
when(messageAfter.getContentRaw()).thenReturn(contentAfterwards); when(messageAfter.getChannelId()).thenReturn(CHANNEL_ID);
when(messageAfter.getTextChannel()).thenReturn(channel);
Guild guild = Mockito.mock(Guild.class); Guild guild = Mockito.mock(Guild.class);
when(messageAfter.getGuild()).thenReturn(guild); when(channel.getGuild()).thenReturn(guild);
Member member = Mockito.mock(Member.class); when(messageAfter.getServerId()).thenReturn(SERVER_ID);
when(messageAfter.getMember()).thenReturn(member); Member author = Mockito.mock(Member.class);
CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
when(cachedAuthor.getAuthorId()).thenReturn(AUTHOR_ID);
when(messageAfter.getAuthor()).thenReturn(cachedAuthor);
when(messageBefore.getContent()).thenReturn(content); when(messageBefore.getContent()).thenReturn(content);
when(messageBefore.getServerId()).thenReturn(serverId); when(messageBefore.getServerId()).thenReturn(SERVER_ID);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class); MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
ArgumentCaptor<MessageEditedLog> captor = ArgumentCaptor.forClass(MessageEditedLog.class); ArgumentCaptor<MessageEditedLog> captor = ArgumentCaptor.forClass(MessageEditedLog.class);
when(templateService.renderEmbedTemplate(eq(MessageEditedListener.MESSAGE_EDITED_TEMPLATE), captor.capture())).thenReturn(messageToSend); when(templateService.renderEmbedTemplate(eq(MessageEditedListener.MESSAGE_EDITED_TEMPLATE), captor.capture())).thenReturn(messageToSend);
when(botService.getMemberInServerAsync(SERVER_ID, AUTHOR_ID)).thenReturn(CompletableFuture.completedFuture(author));
when(botService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(channel);
testUnit.execute(messageBefore, messageAfter); testUnit.execute(messageBefore, messageAfter);
verify(postTargetService, times(1)).sendEmbedInPostTarget(messageToSend, LoggingPostTarget.EDIT_LOG, serverId); verify(postTargetService, times(1)).sendEmbedInPostTarget(messageToSend, LoggingPostTarget.EDIT_LOG, SERVER_ID);
MessageEditedLog capturedValue = captor.getValue(); MessageEditedLog capturedValue = captor.getValue();
Assert.assertEquals(messageBefore, capturedValue.getMessageBefore()); Assert.assertEquals(messageBefore, capturedValue.getMessageBefore());
Assert.assertEquals(messageAfter, capturedValue.getMessageAfter()); Assert.assertEquals(messageAfter, capturedValue.getMessageAfter());
Assert.assertEquals(channel, capturedValue.getMessageChannel()); Assert.assertEquals(channel, capturedValue.getMessageChannel());
Assert.assertEquals(guild, capturedValue.getGuild()); Assert.assertEquals(guild, capturedValue.getGuild());
Assert.assertEquals(member, capturedValue.getMember()); Assert.assertEquals(author, capturedValue.getMember());
} }
} }

View File

@@ -302,6 +302,7 @@ public class MuteServiceBeanTest {
when(muteManagementService.hasActiveMute(userBeingMuted)).thenReturn(true); when(muteManagementService.hasActiveMute(userBeingMuted)).thenReturn(true);
when(muteManagementService.getAMuteOf(userBeingMuted)).thenReturn(mute); when(muteManagementService.getAMuteOf(userBeingMuted)).thenReturn(mute);
when(mute.getMuteId()).thenReturn(new ServerSpecificId(SERVER_ID, MUTE_ID)); when(mute.getMuteId()).thenReturn(new ServerSpecificId(SERVER_ID, MUTE_ID));
when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
testUnit.unMuteUser(userBeingMuted); testUnit.unMuteUser(userBeingMuted);
verifyNoUnMuteHappened(); verifyNoUnMuteHappened();
} }

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.moderation.models.template.listener; package dev.sheldan.abstracto.moderation.models.template.listener;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext; import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
@@ -12,7 +12,7 @@ import lombok.experimental.SuperBuilder;
@Getter @Getter
@Setter @Setter
@SuperBuilder @SuperBuilder
public class MessageDeletedAttachmentLog extends UserInitiatedServerContext { public class MessageDeletedAttachmentLog extends SlimUserInitiatedServerContext {
/** /**
* The proxy URL to the attachment which was deleted. * The proxy URL to the attachment which was deleted.
*/ */

View File

@@ -1,7 +1,7 @@
package dev.sheldan.abstracto.moderation.models.template.listener; package dev.sheldan.abstracto.moderation.models.template.listener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext; import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
@@ -12,7 +12,7 @@ import lombok.experimental.SuperBuilder;
@Getter @Getter
@Setter @Setter
@SuperBuilder @SuperBuilder
public class MessageDeletedLog extends UserInitiatedServerContext { public class MessageDeletedLog extends SlimUserInitiatedServerContext {
/** /**
* A {@link CachedMessage} representing the deleted message * A {@link CachedMessage} representing the deleted message
*/ */

View File

@@ -5,7 +5,6 @@ import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
import net.dv8tion.jda.api.entities.Message;
/** /**
* Used when rendering the log message when a message was edited. The template is: "message_edited_embed" * Used when rendering the log message when a message was edited. The template is: "message_edited_embed"
@@ -15,9 +14,9 @@ import net.dv8tion.jda.api.entities.Message;
@SuperBuilder @SuperBuilder
public class MessageEditedLog extends UserInitiatedServerContext { public class MessageEditedLog extends UserInitiatedServerContext {
/** /**
* The {@link Message} instance which contains the new content of the message * The {@link CachedMessage} instance which contains the new content of the message
*/ */
private Message messageAfter; private CachedMessage messageAfter;
/** /**
* The {@link CachedMessage} which contains the message before the edit was made * The {@link CachedMessage} which contains the message before the edit was made

View File

@@ -18,7 +18,7 @@ public interface MuteService {
String startUnMuteJobFor(Instant unMuteDate, Long muteId, Long serverId); String startUnMuteJobFor(Instant unMuteDate, Long muteId, Long serverId);
void cancelUnMuteJob(Mute mute); void cancelUnMuteJob(Mute mute);
CompletableFuture<Void> unMuteUser(AUserInAServer aUserInAServer); CompletableFuture<Void> unMuteUser(AUserInAServer aUserInAServer);
CompletableFuture<Void> endMute(Mute mute); CompletableFuture<Void> endMute(Mute mute, Boolean sendNotification);
CompletableFuture<Void> endMute(Long muteId, Long serverId); CompletableFuture<Void> endMute(Long muteId, Long serverId);
void completelyUnMuteUser(AUserInAServer aUserInAServer); void completelyUnMuteUser(AUserInAServer aUserInAServer);
void completelyUnMuteMember(Member member); void completelyUnMuteMember(Member member);

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.modmail.listener; package dev.sheldan.abstracto.modmail.listener;
import dev.sheldan.abstracto.core.listener.ServerConfigListener; import dev.sheldan.abstracto.core.listener.sync.entity.ServerConfigListener;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService; import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean; import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;

View File

@@ -1,10 +1,7 @@
package dev.sheldan.abstracto.modmail.listener; package dev.sheldan.abstracto.modmail.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.listener.MessageDeletedListener;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.GuildChannelMember;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.MessageService; import dev.sheldan.abstracto.core.service.MessageService;
@@ -22,7 +19,7 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j @Slf4j
public class ModMailMessageDeletedListener implements MessageDeletedListener { public class ModMailMessageDeletedListener implements AsyncMessageDeletedListener {
@Autowired @Autowired
private ModMailMessageManagementService modMailMessageManagementService; private ModMailMessageManagementService modMailMessageManagementService;
@@ -37,7 +34,7 @@ public class ModMailMessageDeletedListener implements MessageDeletedListener {
private BotService botService; private BotService botService;
@Override @Override
public void execute(CachedMessage messageBefore, AServerAChannelAUser authorUser, GuildChannelMember authorMember) { public void execute(CachedMessage messageBefore) {
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageBefore.getMessageId()); Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageBefore.getMessageId());
messageOptional.ifPresent(modMailMessage -> { messageOptional.ifPresent(modMailMessage -> {
ModMailThread thread = modMailMessage.getThreadReference(); ModMailThread thread = modMailMessage.getThreadReference();
@@ -76,8 +73,4 @@ public class ModMailMessageDeletedListener implements MessageDeletedListener {
return ModMailFeatures.MOD_MAIL; return ModMailFeatures.MOD_MAIL;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -4,8 +4,7 @@ import dev.sheldan.abstracto.core.command.config.Parameters;
import dev.sheldan.abstracto.core.command.service.CommandRegistry; import dev.sheldan.abstracto.core.command.service.CommandRegistry;
import dev.sheldan.abstracto.core.command.service.CommandService; import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageTextUpdatedListener;
import dev.sheldan.abstracto.core.listener.MessageTextUpdatedListener;
import dev.sheldan.abstracto.core.models.FullUserInServer; import dev.sheldan.abstracto.core.models.FullUserInServer;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
@@ -32,7 +31,7 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j @Slf4j
public class ModMailMessageEditedListener implements MessageTextUpdatedListener { public class ModMailMessageEditedListener implements AsyncMessageTextUpdatedListener {
public static final String DEFAULT_COMMAND_FOR_MODMAIL_EDIT = "reply"; public static final String DEFAULT_COMMAND_FOR_MODMAIL_EDIT = "reply";
@Autowired @Autowired
@@ -63,32 +62,40 @@ public class ModMailMessageEditedListener implements MessageTextUpdatedListener
private ModMailThreadService modMailThreadService; private ModMailThreadService modMailThreadService;
@Override @Override
public void execute(CachedMessage messageBefore, Message messageAfter) { public void execute(CachedMessage messageBefore, CachedMessage messageAfter) {
if(!modMailThreadService.isModMailThread(messageBefore.getChannelId())) { if(!modMailThreadService.isModMailThread(messageBefore.getChannelId())) {
return; return;
} }
messageService.loadMessageFromCachedMessage(messageAfter).thenAccept(loadedMessage ->
self.executeMessageUpdatedLogic(messageBefore, messageAfter, loadedMessage)
);
}
@Transactional
public void executeMessageUpdatedLogic(CachedMessage messageBefore, CachedMessage messageAfter, Message loadedMessage) {
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageBefore.getMessageId()); Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageBefore.getMessageId());
messageOptional.ifPresent(modMailMessage -> { messageOptional.ifPresent(modMailMessage -> {
log.info("Editing send message {} in channel {} in mod mail thread {} in server {}.", messageBefore.getMessageId(), messageBefore.getChannelId(), modMailMessage.getThreadReference().getId(), messageBefore.getServerId()); log.info("Editing send message {} in channel {} in mod mail thread {} in server {}.", messageBefore.getMessageId(), messageBefore.getChannelId(), modMailMessage.getThreadReference().getId(), messageBefore.getServerId());
String contentStripped = messageAfter.getContentRaw(); String contentStripped = messageAfter.getContent();
String commandName = commandRegistry.getCommandName(contentStripped.substring(0, contentStripped.indexOf(" ")), messageBefore.getServerId()); String commandName = commandRegistry.getCommandName(contentStripped.substring(0, contentStripped.indexOf(" ")), messageBefore.getServerId());
if(!commandService.doesCommandExist(commandName)) { if(!commandService.doesCommandExist(commandName)) {
commandName = DEFAULT_COMMAND_FOR_MODMAIL_EDIT; commandName = DEFAULT_COMMAND_FOR_MODMAIL_EDIT;
log.info("Edit did not contain the original command to retrieve the parameters for. Resulting to {}.", DEFAULT_COMMAND_FOR_MODMAIL_EDIT); log.info("Edit did not contain the original command to retrieve the parameters for. Resulting to {}.", DEFAULT_COMMAND_FOR_MODMAIL_EDIT);
} }
CompletableFuture<Parameters> parameterParseFuture = commandService.getParametersForCommand(commandName, messageAfter); CompletableFuture<Parameters> parameterParseFuture = commandService.getParametersForCommand(commandName, loadedMessage);
CompletableFuture<Member> loadTargetUser = botService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getThreadReference().getUser().getUserReference().getId()); CompletableFuture<Member> loadTargetUser = botService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getThreadReference().getUser().getUserReference().getId());
CompletableFuture<Member> loadEditingUser = botService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getAuthor().getUserReference().getId()); CompletableFuture<Member> loadEditingUser = botService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getAuthor().getUserReference().getId());
CompletableFuture.allOf(parameterParseFuture, loadTargetUser, loadEditingUser).thenAccept(unused -> CompletableFuture.allOf(parameterParseFuture, loadTargetUser, loadEditingUser).thenAccept(unused ->
self.updateMessageInThread(messageAfter, parameterParseFuture.join(), loadTargetUser.join(), loadEditingUser.join()) self.updateMessageInThread(loadedMessage, parameterParseFuture.join(), loadTargetUser.join(), loadEditingUser.join())
); );
}); });
} }
@Transactional @Transactional
public void updateMessageInThread(Message messageAfter, Parameters parameters, Member targetMember, Member editingUser) { public void updateMessageInThread(Message loadedMessage, Parameters parameters, Member targetMember, Member editingUser) {
String newText = (String) parameters.getParameters().get(0); String newText = (String) parameters.getParameters().get(0);
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageAfter.getIdLong()); Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(loadedMessage.getIdLong());
messageOptional.ifPresent(modMailMessage -> { messageOptional.ifPresent(modMailMessage -> {
FullUserInServer fullThreadUser = FullUserInServer FullUserInServer fullThreadUser = FullUserInServer
.builder() .builder()
@@ -99,7 +106,7 @@ public class ModMailMessageEditedListener implements MessageTextUpdatedListener
.builder() .builder()
.text(newText) .text(newText)
.modMailThread(modMailMessage.getThreadReference()) .modMailThread(modMailMessage.getThreadReference())
.postedMessage(messageAfter) .postedMessage(loadedMessage)
.anonymous(modMailMessage.getAnonymous()) .anonymous(modMailMessage.getAnonymous())
.threadUser(fullThreadUser); .threadUser(fullThreadUser);
if(modMailMessage.getAnonymous()) { if(modMailMessage.getAnonymous()) {
@@ -122,7 +129,7 @@ public class ModMailMessageEditedListener implements MessageTextUpdatedListener
if(!messageOptional.isPresent()) { if(!messageOptional.isPresent()) {
log.warn("Message {} of user {} in channel {} for server {} for thread about user {} could not be found in the mod mail messages when updating the text.", log.warn("Message {} of user {} in channel {} for server {} for thread about user {} could not be found in the mod mail messages when updating the text.",
messageAfter.getIdLong(), editingUser.getIdLong(), messageAfter.getChannel().getIdLong(), messageAfter.getGuild().getIdLong(), targetMember.getIdLong()); loadedMessage.getIdLong(), editingUser.getIdLong(), loadedMessage.getChannel().getIdLong(), loadedMessage.getGuild().getIdLong(), targetMember.getIdLong());
} }
} }
@@ -131,8 +138,4 @@ public class ModMailMessageEditedListener implements MessageTextUpdatedListener
return ModMailFeatures.MOD_MAIL; return ModMailFeatures.MOD_MAIL;
} }
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
} }

View File

@@ -2,7 +2,7 @@ package dev.sheldan.abstracto.modmail.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.PrivateMessageReceivedListener; import dev.sheldan.abstracto.core.listener.sync.jda.PrivateMessageReceivedListener;
import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserManagementService; import dev.sheldan.abstracto.core.service.management.UserManagementService;

View File

@@ -1,7 +1,5 @@
package dev.sheldan.abstracto.modmail.listener; package dev.sheldan.abstracto.modmail.listener;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.GuildChannelMember;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
@@ -47,12 +45,6 @@ public class ModMailMessageDeletedListenerTest {
@Mock @Mock
private CachedMessage deletedMessage; private CachedMessage deletedMessage;
@Mock
private AServerAChannelAUser origin;
@Mock
private GuildChannelMember jdaOrigin;
@Mock @Mock
private ModMailMessage modMailMessage; private ModMailMessage modMailMessage;
@@ -79,7 +71,7 @@ public class ModMailMessageDeletedListenerTest {
public void testDeleteOutSideOfThread() { public void testDeleteOutSideOfThread() {
when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID); when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.empty()); when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.empty());
testUnit.execute(deletedMessage, origin, jdaOrigin); testUnit.execute(deletedMessage);
verify(botService, times(0)).getMemberInServerAsync(anyLong(), anyLong()); verify(botService, times(0)).getMemberInServerAsync(anyLong(), anyLong());
} }
@@ -102,7 +94,7 @@ public class ModMailMessageDeletedListenerTest {
when(targetMember.getUser()).thenReturn(targetUser); when(targetMember.getUser()).thenReturn(targetUser);
when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember)); when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null)); when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null));
testUnit.execute(deletedMessage, origin, jdaOrigin); testUnit.execute(deletedMessage);
verify(messageService, times(0)).deleteMessageInChannelInServer(eq(SERVER_ID), anyLong(), any()); verify(messageService, times(0)).deleteMessageInChannelInServer(eq(SERVER_ID), anyLong(), any());
verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID); verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID);
} }
@@ -129,7 +121,7 @@ public class ModMailMessageDeletedListenerTest {
when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember)); when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null)); when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null));
when(messageService.deleteMessageInChannelInServer(SERVER_ID, CHANNEL_ID, CREATED_MESSAGE_ID_1)).thenReturn(CompletableFuture.completedFuture(null)); when(messageService.deleteMessageInChannelInServer(SERVER_ID, CHANNEL_ID, CREATED_MESSAGE_ID_1)).thenReturn(CompletableFuture.completedFuture(null));
testUnit.execute(deletedMessage, origin, jdaOrigin); testUnit.execute(deletedMessage);
verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID); verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID);
} }

View File

@@ -73,7 +73,10 @@ public class ModMailMessageEditedListenerTest {
private CachedMessage messageBefore; private CachedMessage messageBefore;
@Mock @Mock
private Message messageAfter; private CachedMessage messageAfter;
@Mock
private Message loadedMessage;
@Mock @Mock
private ModMailMessage modMailMessage; private ModMailMessage modMailMessage;
@@ -109,6 +112,15 @@ public class ModMailMessageEditedListenerTest {
private static final Long USER_ID = 3L; private static final Long USER_ID = 3L;
private static final Long AUTHOR_USER_ID = 9L; private static final Long AUTHOR_USER_ID = 9L;
@Test
public void testMessageLoading() {
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
when(messageService.loadMessageFromCachedMessage(messageAfter)).thenReturn(CompletableFuture.completedFuture(loadedMessage));
testUnit.execute(messageBefore, messageAfter);
verify(self, times(1)).executeMessageUpdatedLogic(messageBefore, messageAfter, loadedMessage);
}
@Test @Test
public void testEditOutsideModMailThread() { public void testEditOutsideModMailThread() {
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(false); when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(false);
@@ -119,17 +131,14 @@ public class ModMailMessageEditedListenerTest {
@Test @Test
public void testEditNotTrackedMessage() { public void testEditNotTrackedMessage() {
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID); when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.empty()); when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.empty());
testUnit.execute(messageBefore, messageAfter); testUnit.executeMessageUpdatedLogic(messageBefore, messageAfter, loadedMessage);
verify(commandRegistry, times(0)).getCommandName(anyString(), anyLong()); verify(commandRegistry, times(0)).getCommandName(anyString(), anyLong());
} }
@Test @Test
public void testEditMessageWithCorrectCommand() { public void testEditMessageWithCorrectCommand() {
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID); when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID); when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
when(messageBefore.getServerId()).thenReturn(SERVER_ID); when(messageBefore.getServerId()).thenReturn(SERVER_ID);
@@ -146,19 +155,18 @@ public class ModMailMessageEditedListenerTest {
AUser authorUser = Mockito.mock(AUser.class); AUser authorUser = Mockito.mock(AUser.class);
when(authorUser.getId()).thenReturn(AUTHOR_USER_ID); when(authorUser.getId()).thenReturn(AUTHOR_USER_ID);
when(authorUserInAServer.getUserReference()).thenReturn(authorUser); when(authorUserInAServer.getUserReference()).thenReturn(authorUser);
when(messageAfter.getContentRaw()).thenReturn(NEW_CONTENT); when(messageAfter.getContent()).thenReturn(NEW_CONTENT);
when(commandRegistry.getCommandName(NEW_COMMAND_PART, SERVER_ID)).thenReturn(NEW_COMMAND_PART); when(commandRegistry.getCommandName(NEW_COMMAND_PART, SERVER_ID)).thenReturn(NEW_COMMAND_PART);
when(commandService.doesCommandExist(NEW_COMMAND_PART)).thenReturn(true); when(commandService.doesCommandExist(NEW_COMMAND_PART)).thenReturn(true);
when(commandService.getParametersForCommand(NEW_COMMAND_PART, messageAfter)).thenReturn(CompletableFuture.completedFuture(parsedParameters)); when(commandService.getParametersForCommand(NEW_COMMAND_PART, loadedMessage)).thenReturn(CompletableFuture.completedFuture(parsedParameters));
when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember)); when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
when(botService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember)); when(botService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
testUnit.execute(messageBefore, messageAfter); testUnit.executeMessageUpdatedLogic(messageBefore, messageAfter, loadedMessage);
verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember); verify(self, times(1)).updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
} }
@Test @Test
public void testEditMessageWithInCorrectCommand() { public void testEditMessageWithInCorrectCommand() {
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID); when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID); when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
when(messageBefore.getServerId()).thenReturn(SERVER_ID); when(messageBefore.getServerId()).thenReturn(SERVER_ID);
@@ -175,19 +183,19 @@ public class ModMailMessageEditedListenerTest {
AUser authorUser = Mockito.mock(AUser.class); AUser authorUser = Mockito.mock(AUser.class);
when(authorUser.getId()).thenReturn(AUTHOR_USER_ID); when(authorUser.getId()).thenReturn(AUTHOR_USER_ID);
when(authorUserInAServer.getUserReference()).thenReturn(authorUser); when(authorUserInAServer.getUserReference()).thenReturn(authorUser);
when(messageAfter.getContentRaw()).thenReturn(NEW_CONTENT); when(messageAfter.getContent()).thenReturn(NEW_CONTENT);
when(commandRegistry.getCommandName(NEW_COMMAND_PART, SERVER_ID)).thenReturn(NEW_COMMAND_PART); when(commandRegistry.getCommandName(NEW_COMMAND_PART, SERVER_ID)).thenReturn(NEW_COMMAND_PART);
when(commandService.doesCommandExist(NEW_COMMAND_PART)).thenReturn(false); when(commandService.doesCommandExist(NEW_COMMAND_PART)).thenReturn(false);
when(commandService.getParametersForCommand(DEFAULT_COMMAND_FOR_MODMAIL_EDIT, messageAfter)).thenReturn(CompletableFuture.completedFuture(parsedParameters)); when(commandService.getParametersForCommand(DEFAULT_COMMAND_FOR_MODMAIL_EDIT, loadedMessage)).thenReturn(CompletableFuture.completedFuture(parsedParameters));
when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember)); when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
when(botService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember)); when(botService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
testUnit.execute(messageBefore, messageAfter); testUnit.executeMessageUpdatedLogic(messageBefore, messageAfter, loadedMessage);
verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember); verify(self, times(1)).updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
} }
@Test @Test
public void testUpdateAnonymousMessageInThreadNotDuplicated() { public void testUpdateAnonymousMessageInThreadNotSentToModMailThreadChannel() {
when(messageAfter.getIdLong()).thenReturn(MESSAGE_ID); when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage)); when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
when(modMailMessage.getAnonymous()).thenReturn(true); when(modMailMessage.getAnonymous()).thenReturn(true);
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null); when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
@@ -199,15 +207,15 @@ public class ModMailMessageEditedListenerTest {
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM)); when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend); when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend);
testUnit.updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember); testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
verify(channelService, times(0)).editMessageInAChannel(eq(messageToSend), any(AChannel.class), anyLong()); verify(channelService, times(0)).editMessageInAChannel(eq(messageToSend), any(AChannel.class), anyLong());
verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID); verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous()); Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous());
} }
@Test @Test
public void testUpdateAnonymousMessageInThreadDuplicated() { public void testUpdateAnonymousMessageInThreadAlsoSendToModMailThreadChannel() {
when(messageAfter.getIdLong()).thenReturn(MESSAGE_ID); when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage)); when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
when(modMailMessage.getAnonymous()).thenReturn(true); when(modMailMessage.getAnonymous()).thenReturn(true);
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID); when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID);
@@ -220,9 +228,10 @@ public class ModMailMessageEditedListenerTest {
AChannel channel = Mockito.mock(AChannel.class); AChannel channel = Mockito.mock(AChannel.class);
when(thread.getChannel()).thenReturn(channel); when(thread.getChannel()).thenReturn(channel);
when(channel.getId()).thenReturn(CHANNEL_ID); when(channel.getId()).thenReturn(CHANNEL_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM)); when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend); when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend);
testUnit.updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember); testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
verify(channelService, times(1)).editMessageInAChannel(eq(messageToSend), eq(channel), eq(CREATED_MESSAGE_ID)); verify(channelService, times(1)).editMessageInAChannel(eq(messageToSend), eq(channel), eq(CREATED_MESSAGE_ID));
verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID); verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous()); Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous());
@@ -230,7 +239,7 @@ public class ModMailMessageEditedListenerTest {
@Test @Test
public void testUpdateMessageInThreadNotDuplicated() { public void testUpdateMessageInThreadNotDuplicated() {
when(messageAfter.getIdLong()).thenReturn(MESSAGE_ID); when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage)); when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
when(modMailMessage.getAnonymous()).thenReturn(false); when(modMailMessage.getAnonymous()).thenReturn(false);
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null); when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
@@ -242,7 +251,7 @@ public class ModMailMessageEditedListenerTest {
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM)); when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend); when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend);
testUnit.updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember); testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
verify(channelService, times(0)).editMessageInAChannel(eq(messageToSend), any(AChannel.class), anyLong()); verify(channelService, times(0)).editMessageInAChannel(eq(messageToSend), any(AChannel.class), anyLong());
verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID); verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous()); Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous());
@@ -250,7 +259,7 @@ public class ModMailMessageEditedListenerTest {
@Test @Test
public void testUpdateMessageInThreadDuplicated() { public void testUpdateMessageInThreadDuplicated() {
when(messageAfter.getIdLong()).thenReturn(MESSAGE_ID); when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage)); when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
when(modMailMessage.getAnonymous()).thenReturn(false); when(modMailMessage.getAnonymous()).thenReturn(false);
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID); when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID);
@@ -265,7 +274,7 @@ public class ModMailMessageEditedListenerTest {
when(channel.getId()).thenReturn(CHANNEL_ID); when(channel.getId()).thenReturn(CHANNEL_ID);
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM)); when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend); when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture())).thenReturn(messageToSend);
testUnit.updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember); testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
verify(channelService, times(1)).editMessageInAChannel(eq(messageToSend), eq(channel), eq(CREATED_MESSAGE_ID)); verify(channelService, times(1)).editMessageInAChannel(eq(messageToSend), eq(channel), eq(CREATED_MESSAGE_ID));
verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID); verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous()); Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous());

View File

@@ -3,7 +3,8 @@ package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.FeatureMode; import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.EmoteCreatedListener; import dev.sheldan.abstracto.core.listener.async.jda.AsyncEmoteCreatedListener;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures; import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
@@ -22,16 +23,15 @@ import java.util.List;
*/ */
@Component @Component
@Slf4j @Slf4j
public class CreateTrackedEmoteListener implements EmoteCreatedListener { public class CreateTrackedEmoteListener implements AsyncEmoteCreatedListener {
@Autowired @Autowired
private TrackedEmoteManagementService trackedEmoteManagementService; private TrackedEmoteManagementService trackedEmoteManagementService;
@Override @Override
public void emoteCreated(Emote createdEmote) { public void emoteCreated(CachedEmote createdEmote) {
// guild should be available, because we are in the emote created event, and the emote object should come from there log.info("Creating tracked emote {} in server {}.", createdEmote.getServerId(), createdEmote.getEmoteId());
log.info("Creating tracked emote {} in server {}.", createdEmote.getGuild().getIdLong(), createdEmote.getIdLong()); trackedEmoteManagementService.createTrackedEmote(createdEmote);
trackedEmoteManagementService.createTrackedEmote(createdEmote, createdEmote.getGuild());
} }
@Override @Override

View File

@@ -3,7 +3,8 @@ package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.FeatureMode; import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.EmoteDeletedListener; import dev.sheldan.abstracto.core.listener.async.jda.AsyncEmoteDeletedListener;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures; import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
@@ -22,15 +23,15 @@ import java.util.List;
*/ */
@Component @Component
@Slf4j @Slf4j
public class DeleteTrackedEmoteListener implements EmoteDeletedListener { public class DeleteTrackedEmoteListener implements AsyncEmoteDeletedListener {
@Autowired @Autowired
private TrackedEmoteManagementService trackedEmoteManagementService; private TrackedEmoteManagementService trackedEmoteManagementService;
@Override @Override
public void emoteDeleted(Emote deletedEmote) { public void emoteDeleted(CachedEmote deletedEmote) {
log.info("Marking tracked emote {} in gild {} as deleted.", deletedEmote.getId(), deletedEmote.getGuild().getIdLong()); log.info("Marking tracked emote {} in gild {} as deleted.", deletedEmote.getEmoteId(), deletedEmote.getServerId());
trackedEmoteManagementService.markAsDeleted(deletedEmote.getGuild().getIdLong(), deletedEmote.getIdLong()); trackedEmoteManagementService.markAsDeleted(deletedEmote.getServerId(), deletedEmote.getEmoteId());
} }
@Override @Override

View File

@@ -1,14 +1,12 @@
package dev.sheldan.abstracto.statistic.emotes.listener; package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener; import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures; import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.ISnowflake;
import net.dv8tion.jda.api.entities.Message;
import org.apache.commons.collections4.Bag;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -21,17 +19,19 @@ import java.util.stream.Collectors;
* the runtime storage for emote tracking. * the runtime storage for emote tracking.
*/ */
@Component @Component
public class EmoteTrackingListener implements MessageReceivedListener { public class EmoteTrackingListener implements AsyncMessageReceivedListener {
@Autowired @Autowired
private TrackedEmoteService trackedEmoteService; private TrackedEmoteService trackedEmoteService;
@Autowired
private BotService botService;
@Override @Override
public void execute(Message message) { public void execute(CachedMessage message) {
Bag<Emote> emotesBag = message.getEmotesBag(); Map<Long, List<CachedEmote>> collect = message.getEmotes().stream().collect(Collectors.groupingBy(CachedEmote::getEmoteId));
Map<Long, List<Emote>> collect = emotesBag.stream().collect(Collectors.groupingBy(ISnowflake::getIdLong));
collect.values().forEach(groupedEmotes -> collect.values().forEach(groupedEmotes ->
trackedEmoteService.addEmoteToRuntimeStorage(groupedEmotes.get(0), message.getGuild(), (long) groupedEmotes.size()) trackedEmoteService.addEmoteToRuntimeStorage(groupedEmotes.get(0), botService.getGuildById(message.getServerId()), (long) groupedEmotes.size())
); );
} }
@@ -40,8 +40,4 @@ public class EmoteTrackingListener implements MessageReceivedListener {
return StatisticFeatures.EMOTE_TRACKING; return StatisticFeatures.EMOTE_TRACKING;
} }
@Override
public Integer getPriority() {
return ListenerPriority.LOW;
}
} }

View File

@@ -3,12 +3,12 @@ package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.FeatureMode; import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.EmoteUpdatedListener; import dev.sheldan.abstracto.core.listener.async.jda.AsyncEmoteUpdatedListener;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures; import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode; import dev.sheldan.abstracto.statistic.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -20,14 +20,14 @@ import java.util.List;
* if the emote is tracked. This is only executed if the EMOTE_TRACKING feature is enabled,and if the AUTO_TRACK feature mode is enabled. * if the emote is tracked. This is only executed if the EMOTE_TRACKING feature is enabled,and if the AUTO_TRACK feature mode is enabled.
*/ */
@Component @Component
public class UpdateTrackedEmoteListener implements EmoteUpdatedListener { public class UpdateTrackedEmoteListener implements AsyncEmoteUpdatedListener {
@Autowired @Autowired
private TrackedEmoteManagementService trackedEmoteManagementService; private TrackedEmoteManagementService trackedEmoteManagementService;
@Override @Override
public void emoteUpdated(Emote updatedEmote, String oldValue, String newValue) { public void emoteUpdated(CachedEmote updatedEmote, String oldValue, String newValue) {
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByEmote(updatedEmote); TrackedEmote trackedEmote = trackedEmoteManagementService.loadByEmoteId(updatedEmote.getEmoteId(), updatedEmote.getServerId());
trackedEmoteManagementService.changeName(trackedEmote, newValue); trackedEmoteManagementService.changeName(trackedEmote, newValue);
} }

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.statistic.emotes.service; package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Emote; import net.dv8tion.jda.api.entities.Emote;
@@ -26,12 +27,12 @@ public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeServic
} }
@Override @Override
public void addEmoteForServer(Emote emote, Guild guild, boolean external) { public void addEmoteForServer(CachedEmote emote, Guild guild, boolean external) {
addEmoteForServer(emote, guild, 1L, external); addEmoteForServer(emote, guild, 1L, external);
} }
@Override @Override
public void addEmoteForServer(Emote emote, Guild guild, Long count, boolean external) { public void addEmoteForServer(CachedEmote emote, Guild guild, Long count, boolean external) {
takeLock(); takeLock();
try { try {
// generate an appropriate key // generate an appropriate key
@@ -46,7 +47,7 @@ public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeServic
List<PersistingEmote> persistingEmotes = elementsForKey.get(guild.getIdLong()); List<PersistingEmote> persistingEmotes = elementsForKey.get(guild.getIdLong());
Optional<PersistingEmote> existingEmote = persistingEmotes Optional<PersistingEmote> existingEmote = persistingEmotes
.stream() .stream()
.filter(persistingEmote -> persistingEmote.getEmoteId().equals(emote.getIdLong())) .filter(persistingEmote -> persistingEmote.getEmoteId().equals(emote.getEmoteId()))
.findFirst(); .findFirst();
// if it exists already, just increment the counter by the given amount // if it exists already, just increment the counter by the given amount
existingEmote.ifPresent(persistingEmote -> persistingEmote.setCount(persistingEmote.getCount() + count)); existingEmote.ifPresent(persistingEmote -> persistingEmote.setCount(persistingEmote.getCount() + count));
@@ -77,20 +78,20 @@ public class TrackedEmoteRuntimeServiceBean implements TrackedEmoteRuntimeServic
} }
@Override @Override
public PersistingEmote createFromEmote(Guild guild, Emote emote, boolean external) { public PersistingEmote createFromEmote(Guild guild, CachedEmote emote, boolean external) {
return createFromEmote(guild, emote, 1L, external); return createFromEmote(guild, emote, 1L, external);
} }
@Override @Override
public PersistingEmote createFromEmote(Guild guild, Emote emote, Long count, boolean external) { public PersistingEmote createFromEmote(Guild guild, CachedEmote emote, Long count, boolean external) {
String url = external ? emote.getImageUrl() : null; String url = external ? emote.getImageURL() : null;
return PersistingEmote return PersistingEmote
.builder() .builder()
.animated(emote.isAnimated()) .animated(emote.getAnimated())
.emoteId(emote.getIdLong()) .emoteId(emote.getEmoteId())
.external(external) .external(external)
.externalUrl(url) .externalUrl(url)
.emoteName(emote.getName()) .emoteName(emote.getEmoteName())
.count(count) .count(count)
.serverId(guild.getIdLong()) .serverId(guild.getIdLong())
.build(); .build();

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.service; package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.ServerSpecificId; import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.FeatureModeService; import dev.sheldan.abstracto.core.service.FeatureModeService;
@@ -48,24 +49,22 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
private BotService botService; private BotService botService;
@Override @Override
public void addEmoteToRuntimeStorage(List<Emote> emotes, Guild guild) { public void addEmoteToRuntimeStorage(List<CachedEmote> emotes, Guild guild) {
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES); boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
emotes.forEach(emote -> { emotes.forEach(emote -> {
boolean emoteIsFromGuild = emoteService.emoteIsFromGuild(emote, guild);
// either the emote is from the current guild (we always add those) or external emote tracking is enabled (we should always add those) // either the emote is from the current guild (we always add those) or external emote tracking is enabled (we should always add those)
if(externalTrackingEnabled || emoteIsFromGuild) { if(externalTrackingEnabled || !emote.getExternal()) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, !emoteIsFromGuild); trackedEmoteRuntimeService.addEmoteForServer(emote, guild, emote.getExternal());
} }
}); });
} }
@Override @Override
public void addEmoteToRuntimeStorage(Emote emote, Guild guild, Long count) { public void addEmoteToRuntimeStorage(CachedEmote emote, Guild guild, Long count) {
boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES); boolean externalTrackingEnabled = featureModeService.featureModeActive(StatisticFeatures.EMOTE_TRACKING, guild.getIdLong(), EmoteTrackingMode.EXTERNAL_EMOTES);
boolean emoteIsFromGuild = emoteService.emoteIsFromGuild(emote, guild);
// either the emote is from the current guild (we always add those) or external emote tracking is enabled (we should always add those) // either the emote is from the current guild (we always add those) or external emote tracking is enabled (we should always add those)
if(externalTrackingEnabled || emoteIsFromGuild) { if(externalTrackingEnabled || !emote.getExternal()) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, !emoteIsFromGuild); trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, emote.getExternal());
} }
} }

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.service.management; package dev.sheldan.abstracto.statistic.emotes.service.management;
import dev.sheldan.abstracto.core.models.ServerSpecificId; import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.statistic.emotes.exception.TrackedEmoteNotFoundException; import dev.sheldan.abstracto.statistic.emotes.exception.TrackedEmoteNotFoundException;
@@ -37,6 +38,12 @@ public class TrackedEmoteManagementServiceBean implements TrackedEmoteManagement
return createTrackedEmote(emote.getIdLong(), emote.getName(), emote.isAnimated(), true, server); return createTrackedEmote(emote.getIdLong(), emote.getName(), emote.isAnimated(), true, server);
} }
@Override
public TrackedEmote createTrackedEmote(CachedEmote emote) {
AServer server = serverManagementService.loadServer(emote.getServerId());
return createTrackedEmote(emote.getEmoteId(), emote.getEmoteName(), emote.getAnimated(), true, server);
}
@Override @Override
public TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external) { public TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external) {
if(external) { if(external) {

View File

@@ -1,10 +1,9 @@
package dev.sheldan.abstracto.statistic.emotes.listener; package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures; import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -28,13 +27,11 @@ public class CreateTrackedEmoteListenerTest {
public void testEmoteCreated() { public void testEmoteCreated() {
Long serverId = 4L; Long serverId = 4L;
Long emoteId = 5L; Long emoteId = 5L;
Emote emote = Mockito.mock(Emote.class); CachedEmote emote = Mockito.mock(CachedEmote.class);
Guild guild = Mockito.mock(Guild.class); when(emote.getEmoteId()).thenReturn(emoteId);
when(guild.getIdLong()).thenReturn(serverId); when(emote.getServerId()).thenReturn(serverId);
when(emote.getIdLong()).thenReturn(emoteId);
when(emote.getGuild()).thenReturn(guild);
testUnit.emoteCreated(emote); testUnit.emoteCreated(emote);
verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote, guild); verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote);
} }
@Test @Test

View File

@@ -1,10 +1,9 @@
package dev.sheldan.abstracto.statistic.emotes.listener; package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures; import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -28,11 +27,9 @@ public class DeleteTrackedEmoteListenerTest {
public void testEmoteDeleted() { public void testEmoteDeleted() {
Long serverId = 4L; Long serverId = 4L;
Long emoteId = 5L; Long emoteId = 5L;
Emote emote = Mockito.mock(Emote.class); CachedEmote emote = Mockito.mock(CachedEmote.class);
Guild guild = Mockito.mock(Guild.class); when(emote.getEmoteId()).thenReturn(emoteId);
when(guild.getIdLong()).thenReturn(serverId); when(emote.getServerId()).thenReturn(serverId);
when(emote.getIdLong()).thenReturn(emoteId);
when(emote.getGuild()).thenReturn(guild);
testUnit.emoteDeleted(emote); testUnit.emoteDeleted(emote);
verify(trackedEmoteManagementService, times(1)).markAsDeleted(serverId, emoteId); verify(trackedEmoteManagementService, times(1)).markAsDeleted(serverId, emoteId);
} }

View File

@@ -1,12 +1,11 @@
package dev.sheldan.abstracto.statistic.emotes.listener; package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures; import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService; import dev.sheldan.abstracto.statistic.emotes.service.TrackedEmoteService;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import org.apache.commons.collections4.bag.HashBag;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -14,6 +13,9 @@ import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@@ -26,51 +28,58 @@ public class EmoteTrackingListenerTest {
private TrackedEmoteService trackedEmoteService; private TrackedEmoteService trackedEmoteService;
@Mock @Mock
private Message message; private BotService botService;
@Mock @Mock
private Emote emote1; private CachedMessage message;
@Mock @Mock
private Emote emote2; private CachedEmote emote1;
@Mock
private CachedEmote emote2;
@Mock @Mock
private Guild guild; private Guild guild;
private static final Long EMOTE_ID = 4L; private static final Long EMOTE_ID = 4L;
private static final Long SERVER_ID = 3L;
@Test @Test
public void testExecuteOneEmote() { public void testExecuteOneEmote() {
HashBag<Emote> emotesBag = new HashBag<>(); List<CachedEmote> emotesBag = new ArrayList<>();
emotesBag.add(emote1); emotesBag.add(emote1);
when(message.getGuild()).thenReturn(guild); when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag); when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getEmotes()).thenReturn(emotesBag);
testUnit.execute(message); testUnit.execute(message);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L); verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L);
} }
@Test @Test
public void testExecuteOneEmoteMultipleTimes() { public void testExecuteOneEmoteMultipleTimes() {
HashBag<Emote> emotesBag = new HashBag<>(); List<CachedEmote> emotesBag = new ArrayList<>();
when(emote1.getIdLong()).thenReturn(EMOTE_ID); when(emote1.getEmoteId()).thenReturn(EMOTE_ID);
when(emote2.getIdLong()).thenReturn(EMOTE_ID); when(emote2.getEmoteId()).thenReturn(EMOTE_ID);
emotesBag.add(emote1); emotesBag.add(emote1);
emotesBag.add(emote2); emotesBag.add(emote2);
when(message.getGuild()).thenReturn(guild); when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag); when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getEmotes()).thenReturn(emotesBag);
testUnit.execute(message); testUnit.execute(message);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(any(Emote.class), eq(guild), eq(2L)); verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(any(CachedEmote.class), eq(guild), eq(2L));
} }
@Test @Test
public void testExecuteMultipleEmotes() { public void testExecuteMultipleEmotes() {
HashBag<Emote> emotesBag = new HashBag<>(); List<CachedEmote> emotesBag = new ArrayList<>();
when(emote1.getIdLong()).thenReturn(EMOTE_ID); when(emote1.getEmoteId()).thenReturn(EMOTE_ID);
when(emote2.getIdLong()).thenReturn(EMOTE_ID + 1); when(emote2.getEmoteId()).thenReturn(EMOTE_ID + 1);
emotesBag.add(emote1); emotesBag.add(emote1);
emotesBag.add(emote2); emotesBag.add(emote2);
when(message.getGuild()).thenReturn(guild); when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag); when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getEmotes()).thenReturn(emotesBag);
testUnit.execute(message); testUnit.execute(message);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L); verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote2, guild, 1L); verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote2, guild, 1L);
@@ -78,7 +87,7 @@ public class EmoteTrackingListenerTest {
@Test @Test
public void testExecuteNoEmote() { public void testExecuteNoEmote() {
when(message.getEmotesBag()).thenReturn(new HashBag<>()); when(message.getEmotes()).thenReturn(new ArrayList<>());
testUnit.execute(message); testUnit.execute(message);
verify(trackedEmoteService, times(0)).addEmoteToRuntimeStorage(any(), any(), anyLong()); verify(trackedEmoteService, times(0)).addEmoteToRuntimeStorage(any(), any(), anyLong());
} }
@@ -89,8 +98,4 @@ public class EmoteTrackingListenerTest {
Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature()); Assert.assertEquals(StatisticFeatures.EMOTE_TRACKING, testUnit.getFeature());
} }
@Test
public void testPriority() {
Assert.assertEquals(ListenerPriority.LOW, testUnit.getPriority());
}
} }

View File

@@ -1,10 +1,10 @@
package dev.sheldan.abstracto.statistic.emotes.listener; package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.config.StatisticFeatures; import dev.sheldan.abstracto.statistic.config.StatisticFeatures;
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote; import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService; import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -26,9 +26,13 @@ public class UpdateTrackedEmoteListenerTest {
@Test @Test
public void testEmoteUpdated() { public void testEmoteUpdated() {
Emote changedEmote = Mockito.mock(Emote.class); Long serverId = 1L;
Long emoteId = 2L;
CachedEmote changedEmote = Mockito.mock(CachedEmote.class);
when(changedEmote.getServerId()).thenReturn(serverId);
when(changedEmote.getEmoteId()).thenReturn(emoteId);
TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class); TrackedEmote trackedEmote = Mockito.mock(TrackedEmote.class);
when(trackedEmoteManagementService.loadByEmote(changedEmote)).thenReturn(trackedEmote); when(trackedEmoteManagementService.loadByEmoteId(emoteId, serverId)).thenReturn(trackedEmote);
String newValue = "AFTER"; String newValue = "AFTER";
testUnit.emoteUpdated(changedEmote, "BEFORE", newValue); testUnit.emoteUpdated(changedEmote, "BEFORE", newValue);
verify(trackedEmoteManagementService, times(1)).changeName(trackedEmote, newValue); verify(trackedEmoteManagementService, times(1)).changeName(trackedEmote, newValue);

View File

@@ -1,7 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.service; package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@@ -30,7 +30,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
private Guild guild; private Guild guild;
@Mock @Mock
private Emote emote; private CachedEmote emote;
@Mock @Mock
private PersistingEmote persistingEmote; private PersistingEmote persistingEmote;
@@ -46,7 +46,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testCreateFromEmoteFromGuild() { public void testCreateFromEmoteFromGuild() {
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, false); PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, false);
Assert.assertFalse(createdEmote.getExternal()); Assert.assertFalse(createdEmote.getExternal());
Assert.assertNull(createdEmote.getExternalUrl()); Assert.assertNull(createdEmote.getExternalUrl());
@@ -56,8 +56,8 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testCreateFromEmoteExternal() { public void testCreateFromEmoteExternal() {
when(emote.getImageUrl()).thenReturn(URL); when(emote.getImageURL()).thenReturn(URL);
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, true); PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, COUNT, true);
Assert.assertTrue(createdEmote.getExternal()); Assert.assertTrue(createdEmote.getExternal());
Assert.assertEquals(URL, createdEmote.getExternalUrl()); Assert.assertEquals(URL, createdEmote.getExternalUrl());
@@ -67,7 +67,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testCreateFromEmoteOneCountFromGuild() { public void testCreateFromEmoteOneCountFromGuild() {
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, false); PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, false);
Assert.assertFalse(createdEmote.getExternal()); Assert.assertFalse(createdEmote.getExternal());
Assert.assertNull(createdEmote.getExternalUrl()); Assert.assertNull(createdEmote.getExternalUrl());
@@ -77,8 +77,8 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testCreateFromEmoteOneCountExternal() { public void testCreateFromEmoteOneCountExternal() {
when(emote.getImageUrl()).thenReturn(URL); when(emote.getImageURL()).thenReturn(URL);
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, true); PersistingEmote createdEmote = testUnit.createFromEmote(guild, emote, true);
Assert.assertTrue(createdEmote.getExternal()); Assert.assertTrue(createdEmote.getExternal());
Assert.assertEquals(URL, createdEmote.getExternalUrl()); Assert.assertEquals(URL, createdEmote.getExternalUrl());
@@ -89,7 +89,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testEmoteForServerWithoutExistingSecond() { public void testEmoteForServerWithoutExistingSecond() {
doReturn(SECOND).when(testUnit).getKey(); doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(false); when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(false);
testUnit.addEmoteForServer(emote, guild, false); testUnit.addEmoteForServer(emote, guild, false);
@@ -105,7 +105,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testEmoteForServerWithExistingSecondButNotServer() { public void testEmoteForServerWithExistingSecondButNotServer() {
doReturn(SECOND).when(testUnit).getKey(); doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true); when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>(); HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
@@ -121,7 +121,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testEmoteForServerWithExistingSecondAndServerButNotEmote() { public void testEmoteForServerWithExistingSecondAndServerButNotEmote() {
doReturn(SECOND).when(testUnit).getKey(); doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true); when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>(); HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
@@ -139,7 +139,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testEmoteForServerWithExistingSecondAndServerAndEmote() { public void testEmoteForServerWithExistingSecondAndServerAndEmote() {
doReturn(SECOND).when(testUnit).getKey(); doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true); when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>(); HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();
@@ -160,7 +160,7 @@ public class TrackedEmoteRuntimeServiceBeanTest {
@Test @Test
public void testEmoteForServerWithExistingSecondAndServerAndEmoteCustomCount() { public void testEmoteForServerWithExistingSecondAndServerAndEmoteCustomCount() {
doReturn(SECOND).when(testUnit).getKey(); doReturn(SECOND).when(testUnit).getKey();
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(emote.getEmoteId()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true); when(trackedEmoteRunTimeStorage.contains(SECOND)).thenReturn(true);
HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>(); HashMap<Long, List<PersistingEmote>> serverMap = new HashMap<>();

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.service; package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.ServerSpecificId; import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.FeatureModeService; import dev.sheldan.abstracto.core.service.FeatureModeService;
@@ -55,10 +56,16 @@ public class TrackedEmoteServiceBeanTest {
private BotService botService; private BotService botService;
@Mock @Mock
private Emote emote; private CachedEmote emote;
@Mock @Mock
private Emote secondEmote; private CachedEmote secondEmote;
@Mock
private Emote actualEmote;
@Mock
private Emote secondActualEmote;
@Mock @Mock
private Guild guild; private Guild guild;
@@ -88,7 +95,7 @@ public class TrackedEmoteServiceBeanTest {
private ServerSpecificId secondTrackedEmoteServer; private ServerSpecificId secondTrackedEmoteServer;
@Captor @Captor
private ArgumentCaptor<Emote> emoteArgumentCaptor; private ArgumentCaptor<CachedEmote> emoteArgumentCaptor;
@Captor @Captor
private ArgumentCaptor<Boolean> booleanArgumentCaptor; private ArgumentCaptor<Boolean> booleanArgumentCaptor;
@@ -131,7 +138,7 @@ public class TrackedEmoteServiceBeanTest {
bothEmotesExternal(true, true); bothEmotesExternal(true, true);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild); testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(true)); verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), eq(true));
List<Emote> usedEmotes = emoteArgumentCaptor.getAllValues(); List<CachedEmote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size()); Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0)); Assert.assertEquals(emote, usedEmotes.get(0));
Assert.assertEquals(secondEmote, usedEmotes.get(1)); Assert.assertEquals(secondEmote, usedEmotes.get(1));
@@ -143,7 +150,7 @@ public class TrackedEmoteServiceBeanTest {
bothEmotesExternal(true, false); bothEmotesExternal(true, false);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild); testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture()); verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture());
List<Emote> usedEmotes = emoteArgumentCaptor.getAllValues(); List<CachedEmote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size()); Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0)); Assert.assertEquals(emote, usedEmotes.get(0));
Assert.assertEquals(secondEmote, usedEmotes.get(1)); Assert.assertEquals(secondEmote, usedEmotes.get(1));
@@ -167,7 +174,7 @@ public class TrackedEmoteServiceBeanTest {
bothEmotesExternal(false, false); bothEmotesExternal(false, false);
testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild); testUnit.addEmoteToRuntimeStorage(Arrays.asList(emote, secondEmote), guild);
verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture()); verify(trackedEmoteRuntimeService, times(2)).addEmoteForServer(emoteArgumentCaptor.capture(), eq(guild), booleanArgumentCaptor.capture());
List<Emote> usedEmotes = emoteArgumentCaptor.getAllValues(); List<CachedEmote> usedEmotes = emoteArgumentCaptor.getAllValues();
Assert.assertEquals(2, usedEmotes.size()); Assert.assertEquals(2, usedEmotes.size());
Assert.assertEquals(emote, usedEmotes.get(0)); Assert.assertEquals(emote, usedEmotes.get(0));
Assert.assertEquals(secondEmote, usedEmotes.get(1)); Assert.assertEquals(secondEmote, usedEmotes.get(1));
@@ -178,12 +185,12 @@ public class TrackedEmoteServiceBeanTest {
} }
public void bothEmotesExternal(boolean external, boolean external2) { public void bothEmotesExternal(boolean external, boolean external2) {
when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external); when(emote.getExternal()).thenReturn(external);
when(emoteService.emoteIsFromGuild(secondEmote, guild)).thenReturn(!external2); when(secondEmote.getExternal()).thenReturn(external2);
} }
public void isEmoteExternal(boolean external) { public void isEmoteExternal(boolean external) {
when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external); when(emote.getExternal()).thenReturn(external);
} }
public void externalEmotesEnabled(boolean external) { public void externalEmotesEnabled(boolean external) {
@@ -193,9 +200,9 @@ public class TrackedEmoteServiceBeanTest {
@Test @Test
public void testCrateFakeEmote() { public void testCrateFakeEmote() {
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(actualEmote.getIdLong()).thenReturn(EMOTE_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
TrackedEmote fakeTrackedEmote = testUnit.getFakeTrackedEmote(emote, guild); TrackedEmote fakeTrackedEmote = testUnit.getFakeTrackedEmote(actualEmote, guild);
Assert.assertTrue(fakeTrackedEmote.isFake()); Assert.assertTrue(fakeTrackedEmote.isFake());
Assert.assertEquals(EMOTE_ID, fakeTrackedEmote.getTrackedEmoteId().getId()); Assert.assertEquals(EMOTE_ID, fakeTrackedEmote.getTrackedEmoteId().getId());
Assert.assertEquals(SERVER_ID, fakeTrackedEmote.getTrackedEmoteId().getServerId()); Assert.assertEquals(SERVER_ID, fakeTrackedEmote.getTrackedEmoteId().getServerId());
@@ -219,9 +226,9 @@ public class TrackedEmoteServiceBeanTest {
when(secondTrackedEmote.getTrackedEmoteId()).thenReturn(secondTrackedEmoteServer); when(secondTrackedEmote.getTrackedEmoteId()).thenReturn(secondTrackedEmoteServer);
when(secondTrackedEmoteServer.getServerId()).thenReturn(SERVER_ID); when(secondTrackedEmoteServer.getServerId()).thenReturn(SERVER_ID);
when(secondTrackedEmoteServer.getId()).thenReturn(EMOTE_ID_2); when(secondTrackedEmoteServer.getId()).thenReturn(EMOTE_ID_2);
when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote)); when(guild.getEmotes()).thenReturn(Arrays.asList(actualEmote, secondActualEmote));
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(actualEmote.getIdLong()).thenReturn(EMOTE_ID);
when(secondEmote.getIdLong()).thenReturn(EMOTE_ID_2); when(secondActualEmote.getIdLong()).thenReturn(EMOTE_ID_2);
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote))); when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote)));
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(0L, result.getEmotesAdded().longValue()); Assert.assertEquals(0L, result.getEmotesAdded().longValue());
@@ -236,13 +243,13 @@ public class TrackedEmoteServiceBeanTest {
when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID); when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID);
when(trackedEmoteServer.getId()).thenReturn(EMOTE_ID); when(trackedEmoteServer.getId()).thenReturn(EMOTE_ID);
when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote)); when(guild.getEmotes()).thenReturn(Arrays.asList(actualEmote, secondActualEmote));
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(actualEmote.getIdLong()).thenReturn(EMOTE_ID);
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote))); when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote)));
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(1L, result.getEmotesAdded().longValue()); Assert.assertEquals(1L, result.getEmotesAdded().longValue());
Assert.assertEquals(0L, result.getEmotesMarkedDeleted().longValue()); Assert.assertEquals(0L, result.getEmotesMarkedDeleted().longValue());
verify(trackedEmoteManagementService, times(1)).createTrackedEmote(secondEmote, guild); verify(trackedEmoteManagementService, times(1)).createTrackedEmote(secondActualEmote, guild);
verify(trackedEmoteManagementService, times(0)).markAsDeleted(any(TrackedEmote.class)); verify(trackedEmoteManagementService, times(0)).markAsDeleted(any(TrackedEmote.class));
} }
@@ -252,8 +259,8 @@ public class TrackedEmoteServiceBeanTest {
when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer); when(trackedEmote.getTrackedEmoteId()).thenReturn(trackedEmoteServer);
when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID); when(trackedEmoteServer.getServerId()).thenReturn(SERVER_ID);
when(trackedEmoteServer.getId()).thenReturn(EMOTE_ID); when(trackedEmoteServer.getId()).thenReturn(EMOTE_ID);
when(guild.getEmotes()).thenReturn(Arrays.asList(emote)); when(guild.getEmotes()).thenReturn(Arrays.asList(actualEmote));
when(emote.getIdLong()).thenReturn(EMOTE_ID); when(actualEmote.getIdLong()).thenReturn(EMOTE_ID);
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote))); when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>(Arrays.asList(trackedEmote, secondTrackedEmote)));
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(0L, result.getEmotesAdded().longValue()); Assert.assertEquals(0L, result.getEmotesAdded().longValue());
@@ -277,7 +284,7 @@ public class TrackedEmoteServiceBeanTest {
@Test @Test
public void testSynchronizeTrackedEmotesAllEmotesAreNew() { public void testSynchronizeTrackedEmotesAllEmotesAreNew() {
when(guild.getIdLong()).thenReturn(SERVER_ID); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(guild.getEmotes()).thenReturn(Arrays.asList(emote, secondEmote)); when(guild.getEmotes()).thenReturn(Arrays.asList(actualEmote, secondActualEmote));
when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>()); when(trackedEmoteManagementService.getAllActiveTrackedEmoteForServer(SERVER_ID)).thenReturn(new ArrayList<>());
TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild); TrackedEmoteSynchronizationResult result = testUnit.synchronizeTrackedEmotes(guild);
Assert.assertEquals(2L, result.getEmotesAdded().longValue()); Assert.assertEquals(2L, result.getEmotesAdded().longValue());
@@ -417,9 +424,9 @@ public class TrackedEmoteServiceBeanTest {
} }
private void executeCreateFakeTrackedEmoteTest(boolean external) { private void executeCreateFakeTrackedEmoteTest(boolean external) {
when(emoteService.emoteIsFromGuild(emote, guild)).thenReturn(!external); when(emoteService.emoteIsFromGuild(actualEmote, guild)).thenReturn(!external);
testUnit.createTrackedEmote(emote, guild); testUnit.createTrackedEmote(actualEmote, guild);
verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote, guild, external); verify(trackedEmoteManagementService, times(1)).createTrackedEmote(actualEmote, guild, external);
} }
@Test @Test
@@ -464,12 +471,12 @@ public class TrackedEmoteServiceBeanTest {
when(trackedEmote2.getAnimated()).thenReturn(true); when(trackedEmote2.getAnimated()).thenReturn(true);
when(trackedEmote.getTrackedEmoteId()).thenReturn(new ServerSpecificId(SERVER_ID, EMOTE_ID)); when(trackedEmote.getTrackedEmoteId()).thenReturn(new ServerSpecificId(SERVER_ID, EMOTE_ID));
when(trackedEmote2.getTrackedEmoteId()).thenReturn(new ServerSpecificId(SERVER_ID, EMOTE_ID_2)); when(trackedEmote2.getTrackedEmoteId()).thenReturn(new ServerSpecificId(SERVER_ID, EMOTE_ID_2));
when(guild.getEmoteById(EMOTE_ID)).thenReturn(emote); when(guild.getEmoteById(EMOTE_ID)).thenReturn(actualEmote);
Emote emote2 = Mockito.mock(Emote.class); Emote emote2 = Mockito.mock(Emote.class);
when(guild.getEmoteById(EMOTE_ID_2)).thenReturn(emote2); when(guild.getEmoteById(EMOTE_ID_2)).thenReturn(emote2);
when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2)); when(trackedEmoteManagementService.getTrackedEmoteForServer(SERVER_ID, true)).thenReturn(Arrays.asList(trackedEmote, trackedEmote2));
TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, true); TrackedEmoteOverview trackedEmoteOverview = testUnit.loadTrackedEmoteOverview(guild, true);
Assert.assertEquals(emote, trackedEmoteOverview.getStaticEmotes().get(0).getEmote()); Assert.assertEquals(actualEmote, trackedEmoteOverview.getStaticEmotes().get(0).getEmote());
Assert.assertEquals(trackedEmote, trackedEmoteOverview.getStaticEmotes().get(0).getTrackedEmote()); Assert.assertEquals(trackedEmote, trackedEmoteOverview.getStaticEmotes().get(0).getTrackedEmote());
Assert.assertEquals(emote2, trackedEmoteOverview.getAnimatedEmotes().get(0).getEmote()); Assert.assertEquals(emote2, trackedEmoteOverview.getAnimatedEmotes().get(0).getEmote());
Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getAnimatedEmotes().get(0).getTrackedEmote()); Assert.assertEquals(trackedEmote2, trackedEmoteOverview.getAnimatedEmotes().get(0).getTrackedEmote());

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.statistic.emotes.service; package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import net.dv8tion.jda.api.entities.Emote; import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
@@ -25,17 +26,17 @@ public interface TrackedEmoteRuntimeService {
* @param guild The {@link Guild} in which the {@link Emote} is used * @param guild The {@link Guild} in which the {@link Emote} is used
* @param external Whether or not the emote is external * @param external Whether or not the emote is external
*/ */
void addEmoteForServer(Emote emote, Guild guild, boolean external); void addEmoteForServer(CachedEmote emote, Guild guild, boolean external);
/** /**
* Adds the given {@link Emote} used in the {@link Guild} to the runtime storage. * Adds the given {@link Emote} used in the {@link Guild} to the runtime storage.
* The necessary lock will be acquired by this method. * The necessary lock will be acquired by this method.
* @param emote The {@link Emote} to add to the runtime storage * @param emote The {@link CachedEmote} to add to the runtime storage
* @param guild The {@link Guild} in which the {@link Emote} is used * @param guild The {@link Guild} in which the {@link Emote} is used
* @param count The amount of usages which should be added * @param count The amount of usages which should be added
* @param external Whether or not the emote is external * @param external Whether or not the emote is external
*/ */
void addEmoteForServer(Emote emote, Guild guild, Long count, boolean external); void addEmoteForServer(CachedEmote emote, Guild guild, Long count, boolean external);
/** /**
* Calculates the key used for the Map containing the emote statistics. * Calculates the key used for the Map containing the emote statistics.
@@ -46,21 +47,21 @@ public interface TrackedEmoteRuntimeService {
/** /**
* Creates a {@link PersistingEmote} from the given parameters. * Creates a {@link PersistingEmote} from the given parameters.
* @param guild The {@link Guild} in which the {@link Emote} is used * @param guild The {@link Guild} in which the {@link Emote} is used
* @param emote The {@link Emote} to create a {@link PersistingEmote} from * @param emote The {@link CachedEmote} to create a {@link PersistingEmote} from
* @param external Whether or not the {@link Emote} is external * @param external Whether or not the {@link Emote} is external
* @return A created {@link PersistingEmote} instance from the {@link Emote} * @return A created {@link PersistingEmote} instance from the {@link Emote}
*/ */
PersistingEmote createFromEmote(Guild guild, Emote emote, boolean external); PersistingEmote createFromEmote(Guild guild, CachedEmote emote, boolean external);
/** /**
* Creates a {@link PersistingEmote} from the given parameters. * Creates a {@link PersistingEmote} from the given parameters.
* @param guild The {@link Guild} in which the {@link Emote} is used * @param guild The {@link Guild} in which the {@link Emote} is used
* @param emote The {@link Emote} to create a {@link PersistingEmote} from * @param emote The {@link CachedEmote} to create a {@link PersistingEmote} from
* @param count The amount of usages the {@link Emote} has been used * @param count The amount of usages the {@link Emote} has been used
* @param external Whether or not the {@link Emote} is external * @param external Whether or not the {@link Emote} is external
* @return A created {@link PersistingEmote} instance from the {@link Emote} * @return A created {@link PersistingEmote} instance from the {@link Emote}
*/ */
PersistingEmote createFromEmote(Guild guild, Emote emote, Long count, boolean external); PersistingEmote createFromEmote(Guild guild, CachedEmote emote, Long count, boolean external);
/** /**
* Acquires the lock which should be used when accessing the runtime storage * Acquires the lock which should be used when accessing the runtime storage

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.statistic.emotes.service; package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview; import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteOverview;
import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult; import dev.sheldan.abstracto.statistic.emotes.model.TrackedEmoteSynchronizationResult;
@@ -20,15 +21,15 @@ public interface TrackedEmoteService {
* @param emotes The list of {@link Emote}s to add to the runtime storage * @param emotes The list of {@link Emote}s to add to the runtime storage
* @param guild The {@link Guild} in which the {@link Emote}s were used and where the usages should be added * @param guild The {@link Guild} in which the {@link Emote}s were used and where the usages should be added
*/ */
void addEmoteToRuntimeStorage(List<Emote> emotes, Guild guild); void addEmoteToRuntimeStorage(List<CachedEmote> emotes, Guild guild);
/** /**
* Adds the given {@link Emote} with the given amount to the runtime storage for the given {@link Guild} * Adds the given {@link Emote} with the given amount to the runtime storage for the given {@link Guild}
* @param emote The {@link Emote} to add to the runtime storage * @param emote The {@link CachedEmote} to add to the runtime storage
* @param guild The {@link Guild} in which the {@link Emote} was used and in which the usage should be added * @param guild The {@link Guild} in which the {@link Emote} was used and in which the usage should be added
* @param count The amount of times which the {@link Emote} has been used and should be reflected in the runtime storage * @param count The amount of times which the {@link Emote} has been used and should be reflected in the runtime storage
*/ */
void addEmoteToRuntimeStorage(Emote emote, Guild guild, Long count); void addEmoteToRuntimeStorage(CachedEmote emote, Guild guild, Long count);
/** /**
* Takes the given map of server_ids with the list of {@link PersistingEmote} and stores the objects in the database * Takes the given map of server_ids with the list of {@link PersistingEmote} and stores the objects in the database

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.service.management; package dev.sheldan.abstracto.statistic.emotes.service.management;
import dev.sheldan.abstracto.core.models.ServerSpecificId; import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.statistic.emotes.exception.TrackedEmoteNotFoundException; import dev.sheldan.abstracto.statistic.emotes.exception.TrackedEmoteNotFoundException;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote; import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
@@ -33,6 +34,13 @@ public interface TrackedEmoteManagementService {
*/ */
TrackedEmote createTrackedEmote(Emote emote, Guild guild); TrackedEmote createTrackedEmote(Emote emote, Guild guild);
/**
* Creates and persists a {@link TrackedEmote} for which tracking is enabled based on the given {@link Emote} and {@link Guild}
* @param emote The {@link CachedEmote} to be used to create a {@link TrackedEmote}
* @return The created {@link TrackedEmote} instance in the database
*/
TrackedEmote createTrackedEmote(CachedEmote emote);
/** /**
* Creates and persist a {@link TrackedEmote} for which tracking is enabled based on the given {@link Emote} and {@link Guild} * Creates and persist a {@link TrackedEmote} for which tracking is enabled based on the given {@link Emote} and {@link Guild}
* @param emote The {@link Emote} to be used to create a {@link TrackedEmote} * @param emote The {@link Emote} to be used to create a {@link TrackedEmote}

View File

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo; import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter; import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.execution.ContextConverter;
@@ -19,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -60,8 +62,8 @@ public class Roll extends AbstractConditionableCommand {
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("high").type(Integer.class).templated(true).optional(true).build()); parameters.add(Parameter.builder().name("high").type(Integer.class).templated(true).validators(Arrays.asList(MinIntegerValueValidator.min(2L))).optional(true).build());
parameters.add(Parameter.builder().name("low").type(Integer.class).templated(true).optional(true).build()); parameters.add(Parameter.builder().name("low").type(Integer.class).templated(true).validators(Arrays.asList(MinIntegerValueValidator.min(0L))).optional(true).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("roll") .name("roll")

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.config; package dev.sheldan.abstracto.utility.config;
import dev.sheldan.abstracto.core.listener.ServerConfigListener; import dev.sheldan.abstracto.core.listener.sync.entity.ServerConfigListener;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService; import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService; import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;

View File

@@ -2,7 +2,9 @@ package dev.sheldan.abstracto.utility.listener.embed;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener; import dev.sheldan.abstracto.core.listener.sync.jda.MessageReceivedListener;
import dev.sheldan.abstracto.core.execution.result.ExecutionResult;
import dev.sheldan.abstracto.core.execution.result.MessageReceivedListenerResult;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.MessageCache; import dev.sheldan.abstracto.core.service.MessageCache;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
@@ -11,6 +13,7 @@ import dev.sheldan.abstracto.utility.models.MessageEmbedLink;
import dev.sheldan.abstracto.utility.service.MessageEmbedService; import dev.sheldan.abstracto.utility.service.MessageEmbedService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.Event;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -36,7 +39,7 @@ public class MessageEmbedListener implements MessageReceivedListener {
private MessageEmbedListener self; private MessageEmbedListener self;
@Override @Override
public void execute(Message message) { public MessageReceivedListenerResult execute(Message message) {
String messageRaw = message.getContentRaw(); String messageRaw = message.getContentRaw();
List<MessageEmbedLink> links = messageEmbedService.getLinksInMessage(messageRaw); List<MessageEmbedLink> links = messageEmbedService.getLinksInMessage(messageRaw);
if(!links.isEmpty()) { if(!links.isEmpty()) {
@@ -59,7 +62,12 @@ public class MessageEmbedListener implements MessageReceivedListener {
} }
if(StringUtils.isBlank(messageRaw) && !links.isEmpty()) { if(StringUtils.isBlank(messageRaw) && !links.isEmpty()) {
message.delete().queue(); message.delete().queue();
return MessageReceivedListenerResult.DELETED;
} }
if(!links.isEmpty()) {
return MessageReceivedListenerResult.PROCESSED;
}
return MessageReceivedListenerResult.IGNORED;
} }
@Transactional @Transactional
@@ -73,6 +81,11 @@ public class MessageEmbedListener implements MessageReceivedListener {
}); });
} }
@Override
public boolean shouldConsume(Event event, ExecutionResult result) {
return result.equals(MessageReceivedListenerResult.DELETED);
}
@Override @Override
public FeatureEnum getFeature() { public FeatureEnum getFeature() {
return UtilityFeature.LINK_EMBEDS; return UtilityFeature.LINK_EMBEDS;

View File

@@ -1,12 +1,11 @@
package dev.sheldan.abstracto.utility.listener.embed; package dev.sheldan.abstracto.utility.listener.embed;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
import dev.sheldan.abstracto.core.listener.ReactedAddedListener; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReactions;
import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AEmote;
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.BotService;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.MessageService; import dev.sheldan.abstracto.core.service.MessageService;
@@ -14,8 +13,6 @@ import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage; import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage;
import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService; import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -23,7 +20,7 @@ import java.util.Optional;
@Component @Component
@Slf4j @Slf4j
public class MessageEmbedRemovalReactionListener implements ReactedAddedListener { public class MessageEmbedRemovalReactionListener implements AsyncReactionAddedListener {
public static final String REMOVAL_EMOTE = "removeEmbed"; public static final String REMOVAL_EMOTE = "removeEmbed";
@@ -39,19 +36,16 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
@Autowired @Autowired
private EmoteService emoteService; private EmoteService emoteService;
@Override @Override
public void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent event, AUserInAServer userAdding) { public void executeReactionAdded(CachedMessage message, CachedReactions cachedReaction, ServerUser serverUser) {
Long guildId = message.getServerId(); Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(REMOVAL_EMOTE, guildId); AEmote aEmote = emoteService.getEmoteOrDefaultEmote(REMOVAL_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote(); if(emoteService.compareCachedEmoteWithAEmote(cachedReaction.getEmote(), aEmote)) {
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) {
Optional<EmbeddedMessage> embeddedMessageOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId()); Optional<EmbeddedMessage> embeddedMessageOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId());
if(embeddedMessageOptional.isPresent()) { if(embeddedMessageOptional.isPresent()) {
EmbeddedMessage embeddedMessage = embeddedMessageOptional.get(); EmbeddedMessage embeddedMessage = embeddedMessageOptional.get();
AUser userReacting = userAdding.getUserReference(); if(embeddedMessage.getEmbeddedUser().getUserReference().getId().equals(serverUser.getUserId())
if(embeddedMessage.getEmbeddedUser().getUserReference().getId().equals(userReacting.getId()) || embeddedMessage.getEmbeddingUser().getUserReference().getId().equals(serverUser.getUserId())
|| 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()); log.info("Removing embed in message {} in channel {} in server {} because of a user reaction.", message.getMessageId(), message.getChannelId(), message.getServerId());
messageService.deleteMessageInChannelInServer(message.getServerId(), message.getChannelId(), message.getMessageId()).thenAccept(aVoid ->{ messageService.deleteMessageInChannelInServer(message.getServerId(), message.getChannelId(), message.getMessageId()).thenAccept(aVoid ->{
@@ -74,8 +68,4 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
return UtilityFeature.LINK_EMBEDS; return UtilityFeature.LINK_EMBEDS;
} }
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
} }

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.listener.repost; package dev.sheldan.abstracto.utility.listener.repost;
import dev.sheldan.abstracto.core.listener.entity.ChannelGroupCreatedListener; import dev.sheldan.abstracto.core.listener.sync.entity.ChannelGroupCreatedListener;
import dev.sheldan.abstracto.core.models.database.AChannelGroup; import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.utility.service.RepostServiceBean; import dev.sheldan.abstracto.utility.service.RepostServiceBean;
import dev.sheldan.abstracto.utility.service.management.RepostCheckChannelGroupManagement; import dev.sheldan.abstracto.utility.service.management.RepostCheckChannelGroupManagement;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.listener.repost; package dev.sheldan.abstracto.utility.listener.repost;
import dev.sheldan.abstracto.core.listener.entity.ChannelGroupDeletedListener; import dev.sheldan.abstracto.core.listener.sync.entity.ChannelGroupDeletedListener;
import dev.sheldan.abstracto.core.models.database.AChannelGroup; import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.utility.service.RepostServiceBean; import dev.sheldan.abstracto.utility.service.RepostServiceBean;
import dev.sheldan.abstracto.utility.service.management.RepostCheckChannelGroupManagement; import dev.sheldan.abstracto.utility.service.management.RepostCheckChannelGroupManagement;

View File

@@ -1,9 +1,11 @@
package dev.sheldan.abstracto.utility.listener.repost; package dev.sheldan.abstracto.utility.listener.repost;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageEmbeddedListener;
import dev.sheldan.abstracto.core.listener.MessageEmbeddedListener; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel; import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.service.RepostCheckChannelService; import dev.sheldan.abstracto.utility.service.RepostCheckChannelService;
import dev.sheldan.abstracto.utility.service.RepostService; import dev.sheldan.abstracto.utility.service.RepostService;
@@ -19,7 +21,7 @@ import java.util.stream.Collectors;
@Component @Component
@Slf4j @Slf4j
public class RepostEmbedListener implements MessageEmbeddedListener { public class RepostEmbedListener implements AsyncMessageEmbeddedListener {
@Autowired @Autowired
private RepostCheckChannelService repostCheckChannelService; private RepostCheckChannelService repostCheckChannelService;
@@ -30,15 +32,22 @@ public class RepostEmbedListener implements MessageEmbeddedListener {
@Autowired @Autowired
private PostedImageManagement repostManagement; private PostedImageManagement repostManagement;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private BotService botService;
@Override @Override
public void execute(GuildMessageEmbedEventModel eventModel) { public void execute(GuildMessageEmbedEventModel eventModel) {
if(repostCheckChannelService.duplicateCheckEnabledForChannel(eventModel.getChannel())) { AChannel channel = channelManagementService.loadChannel(eventModel.getChannelId());
if(repostCheckChannelService.duplicateCheckEnabledForChannel(channel)) {
if(repostManagement.messageEmbedsHaveBeenCovered(eventModel.getMessageId())) { if(repostManagement.messageEmbedsHaveBeenCovered(eventModel.getMessageId())) {
log.info("The embeds of the message {} in channel {} in server {} have already been covered by repost check -- ignoring.", log.info("The embeds of the message {} in channel {} in server {} have already been covered by repost check -- ignoring.",
eventModel.getMessageId(), eventModel.getChannel().getIdLong(), eventModel.getChannel().getGuild().getIdLong()); eventModel.getMessageId(), eventModel.getChannelId(), eventModel.getServerId());
return; return;
} }
eventModel.getChannel().retrieveMessageById(eventModel.getMessageId()).queue(message -> { botService.getTextChannelFromServer(eventModel.getServerId(), eventModel.getChannelId()).retrieveMessageById(eventModel.getMessageId()).queue(message -> {
List<MessageEmbed> imageEmbeds = eventModel.getEmbeds().stream().filter(messageEmbed -> messageEmbed.getType().equals(EmbedType.IMAGE)).collect(Collectors.toList()); List<MessageEmbed> imageEmbeds = eventModel.getEmbeds().stream().filter(messageEmbed -> messageEmbed.getType().equals(EmbedType.IMAGE)).collect(Collectors.toList());
repostService.processMessageEmbedsRepostCheck(imageEmbeds, message); repostService.processMessageEmbedsRepostCheck(imageEmbeds, message);
}); });
@@ -50,9 +59,4 @@ public class RepostEmbedListener implements MessageEmbeddedListener {
return UtilityFeature.REPOST_DETECTION; return UtilityFeature.REPOST_DETECTION;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -1,15 +1,16 @@
package dev.sheldan.abstracto.utility.listener.repost; package dev.sheldan.abstracto.utility.listener.repost;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener; import dev.sheldan.abstracto.core.models.cache.CachedEmbed;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.service.RepostCheckChannelService; import dev.sheldan.abstracto.utility.service.RepostCheckChannelService;
import dev.sheldan.abstracto.utility.service.RepostService; import dev.sheldan.abstracto.utility.service.RepostService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.EmbedType; import net.dv8tion.jda.api.entities.EmbedType;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -19,7 +20,7 @@ import java.util.stream.Collectors;
@Component @Component
@Slf4j @Slf4j
public class RepostMessageReceivedListener implements MessageReceivedListener { public class RepostMessageReceivedListener implements AsyncMessageReceivedListener {
@Autowired @Autowired
private RepostCheckChannelService repostCheckChannelService; private RepostCheckChannelService repostCheckChannelService;
@@ -27,11 +28,15 @@ public class RepostMessageReceivedListener implements MessageReceivedListener {
@Autowired @Autowired
private RepostService repostService; private RepostService repostService;
@Autowired
private ChannelManagementService channelManagementService;
@Override @Override
public void execute(Message message) { public void execute(CachedMessage message) {
if(repostCheckChannelService.duplicateCheckEnabledForChannel(message.getTextChannel())) { AChannel channel = channelManagementService.loadChannel(message.getChannelId());
if(repostCheckChannelService.duplicateCheckEnabledForChannel(channel)) {
repostService.processMessageAttachmentRepostCheck(message); repostService.processMessageAttachmentRepostCheck(message);
List<MessageEmbed> imageEmbeds = message.getEmbeds().stream().filter(messageEmbed -> messageEmbed.getType().equals(EmbedType.IMAGE)).collect(Collectors.toList()); List<CachedEmbed> imageEmbeds = message.getEmbeds().stream().filter(messageEmbed -> messageEmbed.getType().equals(EmbedType.IMAGE)).collect(Collectors.toList());
repostService.processMessageEmbedsRepostCheck(imageEmbeds, message); repostService.processMessageEmbedsRepostCheck(imageEmbeds, message);
} }
} }
@@ -41,8 +46,4 @@ public class RepostMessageReceivedListener implements MessageReceivedListener {
return UtilityFeature.REPOST_DETECTION; return UtilityFeature.REPOST_DETECTION;
} }
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
} }

View File

@@ -1,12 +1,12 @@
package dev.sheldan.abstracto.utility.listener.starboard; package dev.sheldan.abstracto.utility.listener.starboard;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
import dev.sheldan.abstracto.core.listener.ReactedAddedListener; import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionClearedListener;
import dev.sheldan.abstracto.core.listener.ReactedRemovedListener; import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionRemovedListener;
import dev.sheldan.abstracto.core.listener.ReactionClearedListener; import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReaction; import dev.sheldan.abstracto.core.models.cache.CachedReactions;
import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.BotService;
@@ -19,9 +19,6 @@ import dev.sheldan.abstracto.utility.service.StarboardService;
import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService; import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService;
import dev.sheldan.abstracto.utility.service.management.StarboardPostReactorManagementService; import dev.sheldan.abstracto.utility.service.management.StarboardPostReactorManagementService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -33,7 +30,7 @@ import java.util.stream.Collectors;
@Component @Component
@Slf4j @Slf4j
public class StarboardListener implements ReactedAddedListener, ReactedRemovedListener, ReactionClearedListener { public class StarboardListener implements AsyncReactionAddedListener, AsyncReactionRemovedListener, AsyncReactionClearedListener {
public static final String STAR_EMOTE = "star"; public static final String STAR_EMOTE = "star";
public static final String FIRST_LEVEL_THRESHOLD_KEY = "starLvl1"; public static final String FIRST_LEVEL_THRESHOLD_KEY = "starLvl1";
@@ -61,34 +58,34 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
@Override @Override
@Transactional @Transactional
public void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent addedReaction, AUserInAServer userAdding) { public void executeReactionAdded(CachedMessage message, CachedReactions cachedReaction, ServerUser serverUser) {
if(userAdding.getUserReference().getId().equals(message.getAuthorId())) { if(serverUser.getUserId().equals(message.getAuthor().getAuthorId())) {
return; return;
} }
Long guildId = message.getServerId(); Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId); AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = addedReaction.getReactionEmote(); if(emoteService.compareCachedEmoteWithAEmote(cachedReaction.getEmote(), aEmote)) {
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) { log.info("User {} in server {} reacted with star to put a message {} from channel {} on starboard.", serverUser.getUserId(), message.getServerId(), message.getMessageId(), message.getChannelId());
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<CachedReactions> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote); handleStarboardPostChange(message, reactionOptional.orElse(null), serverUser, true);
handleStarboardPostChange(message, reactionOptional.orElse(null), userAdding, true);
} }
} }
private void handleStarboardPostChange(CachedMessage message, CachedReaction reaction, AUserInAServer userReacting, boolean adding) { private void handleStarboardPostChange(CachedMessage message, CachedReactions reaction, ServerUser serverUser, boolean adding) {
Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId()); Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId());
if(reaction != null) { if(reaction != null) {
AUserInAServer author = userInServerManagementService.loadUser(message.getServerId(), message.getAuthorId()); AUserInAServer author = userInServerManagementService.loadUser(message.getServerId(), message.getAuthor().getAuthorId());
List<AUserInAServer> userExceptAuthor = getUsersExcept(reaction.getUserInServersIds(), author); List<AUserInAServer> userExceptAuthor = getUsersExcept(reaction.getUsers(), author);
Long starMinimum = getFromConfig(FIRST_LEVEL_THRESHOLD_KEY, message.getServerId()); Long starMinimum = getFromConfig(FIRST_LEVEL_THRESHOLD_KEY, message.getServerId());
AUserInAServer userAddingReaction = userInServerManagementService.loadUser(serverUser);
if (userExceptAuthor.size() >= starMinimum) { if (userExceptAuthor.size() >= starMinimum) {
log.info("Post reached starboard minimum. Message {} in channel {} in server {} will be starred/updated.", log.info("Post reached starboard minimum. Message {} in channel {} in server {} will be starred/updated.",
message.getMessageId(), message.getChannelId(), message.getServerId()); message.getMessageId(), message.getChannelId(), message.getServerId());
if(starboardPostOptional.isPresent()) { if(starboardPostOptional.isPresent()) {
updateStarboardPost(message, userReacting, adding, starboardPostOptional.get(), userExceptAuthor); updateStarboardPost(message, userAddingReaction, adding, starboardPostOptional.get(), userExceptAuthor);
} else { } else {
log.info("Creating starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId()); log.info("Creating starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId());
starboardService.createStarboardPost(message, userExceptAuthor, userReacting, author); starboardService.createStarboardPost(message, userExceptAuthor, userAddingReaction, author);
} }
} else { } else {
if(starboardPostOptional.isPresent()) { if(starboardPostOptional.isPresent()) {
@@ -124,17 +121,16 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
@Override @Override
@Transactional @Transactional
public void executeReactionRemoved(CachedMessage message, GuildMessageReactionRemoveEvent removedReaction, AUserInAServer userRemoving) { public void executeReactionRemoved(CachedMessage message, CachedReactions removedReaction, ServerUser userRemoving) {
if(message.getAuthorId().equals(userRemoving.getUserReference().getId())) { if(message.getAuthor().getAuthorId().equals(userRemoving.getUserId())) {
return; return;
} }
Long guildId = message.getServerId(); Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId); AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = removedReaction.getReactionEmote(); if(emoteService.compareCachedEmoteWithAEmote(removedReaction.getEmote(), aEmote)) {
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) {
log.info("User {} in server {} removed star reaction from message {} on starboard.", log.info("User {} in server {} removed star reaction from message {} on starboard.",
userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), message.getMessageId()); userRemoving.getUserId(), message.getServerId(), message.getMessageId());
Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote); Optional<CachedReactions> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), userRemoving, false); handleStarboardPostChange(message, reactionOptional.orElse(null), userRemoving, false);
} }
} }
@@ -143,9 +139,9 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
return configManagementService.loadConfig(guildId, key).getLongValue(); return configManagementService.loadConfig(guildId, key).getLongValue();
} }
private List<AUserInAServer> getUsersExcept(List<Long> users, AUserInAServer author) { private List<AUserInAServer> getUsersExcept(List<ServerUser> users, AUserInAServer author) {
return users.stream().filter(user -> !user.equals(author.getUserInServerId())).map(aLong -> { return users.stream().filter(user -> !(user.getServerId().equals(author.getServerReference().getId()) && user.getUserId().equals(author.getUserReference().getId()))).map(serverUser -> {
Optional<AUserInAServer> aUserInAServer = userInServerManagementService.loadUserConditional(aLong); Optional<AUserInAServer> aUserInAServer = userInServerManagementService.loadUserOptional(serverUser.getServerId(), serverUser.getUserId());
return aUserInAServer.orElse(null); return aUserInAServer.orElse(null);
}).filter(Objects::nonNull).collect(Collectors.toList()); }).filter(Objects::nonNull).collect(Collectors.toList());
} }
@@ -167,8 +163,4 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
}); });
} }
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
} }

View File

@@ -1,10 +1,7 @@
package dev.sheldan.abstracto.utility.listener.starboard; package dev.sheldan.abstracto.utility.listener.starboard;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority; import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.listener.MessageDeletedListener;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.GuildChannelMember;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.database.StarboardPost; import dev.sheldan.abstracto.utility.models.database.StarboardPost;
@@ -17,18 +14,18 @@ import java.util.Optional;
@Component @Component
@Slf4j @Slf4j
public class StarboardPostDeletedListener implements MessageDeletedListener { public class StarboardPostDeletedListener implements AsyncMessageDeletedListener {
@Autowired @Autowired
private StarboardPostManagementService starboardPostManagementService; private StarboardPostManagementService starboardPostManagementService;
@Override @Override
public void execute(CachedMessage messageBefore, AServerAChannelAUser authorUser, GuildChannelMember authorMember) { public void execute(CachedMessage messageBefore) {
Optional<StarboardPost> byStarboardPostId = starboardPostManagementService.findByStarboardPostId(messageBefore.getMessageId()); Optional<StarboardPost> byStarboardPostId = starboardPostManagementService.findByStarboardPostId(messageBefore.getMessageId());
if(byStarboardPostId.isPresent()) { if(byStarboardPostId.isPresent()) {
StarboardPost post = byStarboardPostId.get(); StarboardPost post = byStarboardPostId.get();
log.info("Removing starboard post: message {}, channel {}, server {}, because the message was deleted", log.info("Removing starboard post: message {}, channel {}, server {}, because the message was deleted",
post.getPostMessageId(), post.getSourceChanel().getId(), post.getAuthor().getUserReference().getId()); post.getPostMessageId(), post.getSourceChanel().getId(), messageBefore.getServerId());
starboardPostManagementService.setStarboardPostIgnored(messageBefore.getMessageId(), true); starboardPostManagementService.setStarboardPostIgnored(messageBefore.getMessageId(), true);
} }
} }
@@ -38,8 +35,4 @@ public class StarboardPostDeletedListener implements MessageDeletedListener {
return UtilityFeature.STARBOARD; return UtilityFeature.STARBOARD;
} }
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
} }

View File

@@ -111,7 +111,7 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
@Override @Override
@Transactional @Transactional
public CompletableFuture<Void> embedLink(CachedMessage cachedMessage, TextChannel target, Long userEmbeddingUserInServerId, Message embeddingMessage) { public CompletableFuture<Void> embedLink(CachedMessage cachedMessage, TextChannel target, Long userEmbeddingUserInServerId, Message embeddingMessage) {
Optional<AUserInAServer> causeOpt = userInServerManagementService.loadUserConditional(userEmbeddingUserInServerId); Optional<AUserInAServer> causeOpt = userInServerManagementService.loadUserOptional(userEmbeddingUserInServerId);
if(causeOpt.isPresent()) { if(causeOpt.isPresent()) {
return buildTemplateParameter(embeddingMessage, cachedMessage).thenCompose(messageEmbeddedModel -> return buildTemplateParameter(embeddingMessage, cachedMessage).thenCompose(messageEmbeddedModel ->
self.sendEmbeddingMessage(cachedMessage, target, userEmbeddingUserInServerId, messageEmbeddedModel) self.sendEmbeddingMessage(cachedMessage, target, userEmbeddingUserInServerId, messageEmbeddedModel)
@@ -145,7 +145,7 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
} }
private CompletableFuture<MessageEmbeddedModel> buildTemplateParameter(Message message, CachedMessage embeddedMessage) { private CompletableFuture<MessageEmbeddedModel> buildTemplateParameter(Message message, CachedMessage embeddedMessage) {
return botService.getMemberInServerAsync(embeddedMessage.getServerId(), embeddedMessage.getAuthorId()).thenApply(member -> return botService.getMemberInServerAsync(embeddedMessage.getServerId(), embeddedMessage.getAuthor().getAuthorId()).thenApply(member ->
self.loadMessageEmbedModel(message, embeddedMessage, member) self.loadMessageEmbedModel(message, embeddedMessage, member)
); );
} }

View File

@@ -1,6 +1,10 @@
package dev.sheldan.abstracto.utility.service; package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser; import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.ServerChannelMessageUser;
import dev.sheldan.abstracto.core.models.cache.CachedAttachment;
import dev.sheldan.abstracto.core.models.cache.CachedEmbed;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.FeatureModeService; import dev.sheldan.abstracto.core.service.FeatureModeService;
@@ -85,10 +89,31 @@ public class RepostServiceBean implements RepostService {
public static final String REPOST_MARKER_EMOTE_KEY = "repostMarker"; public static final String REPOST_MARKER_EMOTE_KEY = "repostMarker";
@Override @Override
public boolean isRepost(Message message, MessageEmbed messageEmbed, Integer index) { public boolean isRepost(CachedMessage message, CachedEmbed messageEmbed, Integer index) {
return getRepostFor(message, messageEmbed, index).isPresent(); return getRepostFor(message, messageEmbed, index).isPresent();
} }
@Override
public Optional<PostedImage> getRepostFor(CachedMessage message, CachedEmbed messageEmbed, Integer embedIndex) {
if(messageEmbed.getCachedThumbnail() == null && messageEmbed.getCachedImageInfo() == null) {
return Optional.empty();
}
String urlToUse = null;
if(messageEmbed.getCachedThumbnail() != null) {
urlToUse = messageEmbed.getCachedThumbnail().getProxyUrl();
} else if (messageEmbed.getCachedImageInfo() != null) {
urlToUse = messageEmbed.getCachedImageInfo().getProxyUrl();
}
ServerChannelMessageUser serverChannelMessageUser = ServerChannelMessageUser
.builder()
.serverId(message.getServerId())
.channelId(message.getChannelId())
.userId(message.getAuthor().getAuthorId())
.messageId(message.getMessageId())
.build();
return checkForDuplicates(serverChannelMessageUser, EMBEDDED_LINK_POSITION_START_INDEX + embedIndex, urlToUse);
}
@Override @Override
public Optional<PostedImage> getRepostFor(Message message, MessageEmbed messageEmbed, Integer embedIndex) { public Optional<PostedImage> getRepostFor(Message message, MessageEmbed messageEmbed, Integer embedIndex) {
if(messageEmbed.getThumbnail() == null && messageEmbed.getImage() == null) { if(messageEmbed.getThumbnail() == null && messageEmbed.getImage() == null) {
@@ -100,38 +125,52 @@ public class RepostServiceBean implements RepostService {
} else if (messageEmbed.getImage() != null) { } else if (messageEmbed.getImage() != null) {
urlToUse = messageEmbed.getImage().getProxyUrl(); urlToUse = messageEmbed.getImage().getProxyUrl();
} }
return checkForDuplicates(message, EMBEDDED_LINK_POSITION_START_INDEX + embedIndex, urlToUse); ServerChannelMessageUser serverChannelMessageUser = ServerChannelMessageUser
.builder()
.serverId(message.getGuild().getIdLong())
.channelId(message.getChannel().getIdLong())
.userId(message.getAuthor().getIdLong())
.messageId(message.getIdLong())
.build();
return checkForDuplicates(serverChannelMessageUser, EMBEDDED_LINK_POSITION_START_INDEX + embedIndex, urlToUse);
} }
private Optional<PostedImage> checkForDuplicates(Message message, Integer index, String fileUrl) { private Optional<PostedImage> checkForDuplicates(ServerChannelMessageUser serverChannelMessageUser, Integer index, String fileUrl) {
String fileHash = calculateHashForPost(fileUrl, message.getGuild().getIdLong()); String fileHash = calculateHashForPost(fileUrl, serverChannelMessageUser.getServerId());
AServer aServer = serverManagementService.loadServer(message.getGuild().getIdLong()); AServer aServer = serverManagementService.loadServer(serverChannelMessageUser.getServerId());
Optional<PostedImage> potentialRepost = postedImageManagement.getPostWithHash(fileHash, aServer); Optional<PostedImage> potentialRepost = postedImageManagement.getPostWithHash(fileHash, aServer);
if(potentialRepost.isPresent()) { if(potentialRepost.isPresent()) {
PostedImage existingRepost = potentialRepost.get(); PostedImage existingRepost = potentialRepost.get();
return existingRepost.getPostId().getMessageId() != message.getIdLong() ? Optional.of(existingRepost) : Optional.empty(); return !existingRepost.getPostId().getMessageId().equals(serverChannelMessageUser.getMessageId()) ? Optional.of(existingRepost) : Optional.empty();
} else { } else {
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(message.getMember()); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(serverChannelMessageUser.getServerId(), serverChannelMessageUser.getUserId());
AServerAChannelAUser cause = AServerAChannelAUser AServerAChannelAUser cause = AServerAChannelAUser
.builder() .builder()
.aUserInAServer(aUserInAServer) .aUserInAServer(aUserInAServer)
.channel(channelManagementService.loadChannel(message.getTextChannel().getIdLong())) .channel(channelManagementService.loadChannel(serverChannelMessageUser.getChannelId()))
.guild(aServer) .guild(aServer)
.user(aUserInAServer.getUserReference()) .user(aUserInAServer.getUserReference())
.build(); .build();
postedImageManagement.createPost(cause, message, fileHash, index); postedImageManagement.createPost(cause, serverChannelMessageUser.getMessageId(), fileHash, index);
return Optional.empty(); return Optional.empty();
} }
} }
@Override @Override
public boolean isRepost(Message message, Message.Attachment attachment, Integer index) { public boolean isRepost(CachedMessage message, CachedAttachment attachment, Integer index) {
return getRepostFor(message, attachment, index).isPresent(); return getRepostFor(message, attachment, index).isPresent();
} }
@Override @Override
public Optional<PostedImage> getRepostFor(Message message, Message.Attachment attachment, Integer index) { public Optional<PostedImage> getRepostFor(CachedMessage message, CachedAttachment attachment, Integer index) {
return checkForDuplicates(message, index, attachment.getProxyUrl()); ServerChannelMessageUser serverChannelMessageUser = ServerChannelMessageUser
.builder()
.serverId(message.getServerId())
.channelId(message.getChannelId())
.userId(message.getAuthor().getAuthorId())
.messageId(message.getMessageId())
.build();
return checkForDuplicates(serverChannelMessageUser, index, attachment.getProxyUrl());
} }
@Override @Override
@@ -159,31 +198,38 @@ public class RepostServiceBean implements RepostService {
} }
@Override @Override
public void processMessageAttachmentRepostCheck(Message message) { public void processMessageAttachmentRepostCheck(CachedMessage message) {
boolean canThereBeMultipleReposts = message.getAttachments().size() > 1; boolean canThereBeMultipleReposts = message.getAttachments().size() > 1;
for (int imageIndex = 0; imageIndex < message.getAttachments().size(); imageIndex++) { for (int imageIndex = 0; imageIndex < message.getAttachments().size(); imageIndex++) {
executeRepostCheckForAttachment(message, message.getAttachments().get(imageIndex), imageIndex, canThereBeMultipleReposts); executeRepostCheckForAttachment(message, message.getAttachments().get(imageIndex), imageIndex, canThereBeMultipleReposts);
} }
} }
private void executeRepostCheckForAttachment(Message message, Message.Attachment attachment, Integer index, boolean moreRepostsPossible) { private void executeRepostCheckForAttachment(CachedMessage message, CachedAttachment attachment, Integer index, boolean moreRepostsPossible) {
Optional<PostedImage> originalPostOptional = getRepostFor(message, attachment, index); Optional<PostedImage> originalPostOptional = getRepostFor(message, attachment, index);
originalPostOptional.ifPresent(postedImage -> markMessageAndPersist(message, index, moreRepostsPossible, postedImage)); ServerChannelMessageUser serverChannelMessageUser = ServerChannelMessageUser
.builder()
.serverId(message.getServerId())
.channelId(message.getChannelId())
.userId(message.getAuthor().getAuthorId())
.messageId(message.getMessageId())
.build();
originalPostOptional.ifPresent(postedImage -> markMessageAndPersist(serverChannelMessageUser, index, moreRepostsPossible, postedImage));
} }
private void markMessageAndPersist(Message message, Integer index, boolean moreRepostsPossible, PostedImage originalPost) { private void markMessageAndPersist(ServerChannelMessageUser messageUser, Integer index, boolean moreRepostsPossible, PostedImage originalPost) {
log.info("Detected repost in message embed {} of message {} in channel {} in server {}.", index, message.getIdLong(), message.getTextChannel().getIdLong(), message.getGuild().getIdLong()); log.info("Detected repost in message embed {} of message {} in channel {} in server {}.", index, messageUser.getMessageId(), messageUser.getChannelId(), messageUser.getServerId());
CompletableFuture<Void> markerFuture = messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, message.getGuild().getIdLong(), message); CompletableFuture<Void> markerFuture = messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, messageUser.getServerId(), messageUser.getChannelId(), messageUser.getMessageId());
CompletableFuture<Void> counterFuture; CompletableFuture<Void> counterFuture;
if (moreRepostsPossible) { if (moreRepostsPossible) {
counterFuture = messageService.addDefaultReactionToMessageAsync(NUMBER_EMOJI.get(index), message); counterFuture = messageService.addDefaultReactionToMessageAsync(NUMBER_EMOJI.get(index), messageUser.getServerId(), messageUser.getChannelId(), messageUser.getMessageId());
} else { } else {
counterFuture = CompletableFuture.completedFuture(null); counterFuture = CompletableFuture.completedFuture(null);
} }
Long messageId = originalPost.getPostId().getMessageId(); Long messageId = originalPost.getPostId().getMessageId();
Integer position = originalPost.getPostId().getPosition(); Integer position = originalPost.getPostId().getPosition();
Long serverId = message.getGuild().getIdLong(); Long serverId = messageUser.getServerId();
Long userId = message.getAuthor().getIdLong(); Long userId = messageUser.getUserId();
CompletableFuture.allOf(markerFuture, counterFuture).thenAccept(unused -> CompletableFuture.allOf(markerFuture, counterFuture).thenAccept(unused ->
self.persistRepost(messageId, position, serverId, userId) self.persistRepost(messageId, position, serverId, userId)
); );
@@ -202,6 +248,14 @@ public class RepostServiceBean implements RepostService {
} }
} }
@Override
public void processMessageEmbedsRepostCheck(List<CachedEmbed> embeds, CachedMessage message) {
boolean canThereBeMultipleReposts = embeds.size() > 1 || !message.getAttachments().isEmpty();
for (int imageIndex = 0; imageIndex < embeds.size(); imageIndex++) {
executeRepostCheckForMessageEmbed(message, embeds.get(imageIndex), imageIndex + message.getAttachments().size(), canThereBeMultipleReposts);
}
}
@Override @Override
public void processMessageEmbedsRepostCheck(List<MessageEmbed> embeds, Message message) { public void processMessageEmbedsRepostCheck(List<MessageEmbed> embeds, Message message) {
boolean canThereBeMultipleReposts = embeds.size() > 1 || !message.getAttachments().isEmpty(); boolean canThereBeMultipleReposts = embeds.size() > 1 || !message.getAttachments().isEmpty();
@@ -228,8 +282,27 @@ public class RepostServiceBean implements RepostService {
repostManagementService.deleteRepostsFromServer(server); repostManagementService.deleteRepostsFromServer(server);
} }
private void executeRepostCheckForMessageEmbed(CachedMessage message, CachedEmbed messageEmbed, Integer index, boolean moreRepostsPossible) {
Optional<PostedImage> originalPostOptional = getRepostFor(message, messageEmbed, index);
ServerChannelMessageUser serverChannelMessageUser = ServerChannelMessageUser
.builder()
.serverId(message.getServerId())
.channelId(message.getChannelId())
.userId(message.getAuthor().getAuthorId())
.messageId(message.getMessageId())
.build();
originalPostOptional.ifPresent(postedImage -> markMessageAndPersist(serverChannelMessageUser, index, moreRepostsPossible, postedImage));
}
private void executeRepostCheckForMessageEmbed(Message message, MessageEmbed messageEmbed, Integer index, boolean moreRepostsPossible) { private void executeRepostCheckForMessageEmbed(Message message, MessageEmbed messageEmbed, Integer index, boolean moreRepostsPossible) {
Optional<PostedImage> originalPostOptional = getRepostFor(message, messageEmbed, index); Optional<PostedImage> originalPostOptional = getRepostFor(message, messageEmbed, index);
originalPostOptional.ifPresent(postedImage -> markMessageAndPersist(message, index, moreRepostsPossible, postedImage)); ServerChannelMessageUser serverChannelMessageUser = ServerChannelMessageUser
.builder()
.serverId(message.getGuild().getIdLong())
.channelId(message.getChannel().getIdLong())
.userId(message.getAuthor().getIdLong())
.messageId(message.getIdLong())
.build();
originalPostOptional.ifPresent(postedImage -> markMessageAndPersist(serverChannelMessageUser, index, moreRepostsPossible, postedImage));
} }
} }

View File

@@ -104,7 +104,7 @@ public class StarboardServiceBean implements StarboardService {
@Transactional @Transactional
public void persistPost(CachedMessage message, List<Long> userExceptAuthorIds, List<CompletableFuture<Message>> completableFutures, Long starboardChannelId, Long starredUserId) { public void persistPost(CachedMessage message, List<Long> userExceptAuthorIds, List<CompletableFuture<Message>> completableFutures, Long starboardChannelId, Long starredUserId) {
AUserInAServer innerStarredUser = userInServerManagementService.loadUserConditional(starredUserId).orElseThrow(() -> new UserInServerNotFoundException(starredUserId)); AUserInAServer innerStarredUser = userInServerManagementService.loadUserOptional(starredUserId).orElseThrow(() -> new UserInServerNotFoundException(starredUserId));
AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId); AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId);
Message message1 = completableFutures.get(0).join(); Message message1 = completableFutures.get(0).join();
AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage
@@ -119,17 +119,18 @@ public class StarboardServiceBean implements StarboardService {
log.warn("There are no user ids except the author for the reactions in post {} in guild {} for message {} in channel {}.", starboardPost.getId(), message.getChannelId(), message.getMessageId(), message.getChannelId()); log.warn("There are no user ids except the author for the reactions in post {} in guild {} for message {} in channel {}.", starboardPost.getId(), message.getChannelId(), message.getMessageId(), message.getChannelId());
} }
userExceptAuthorIds.forEach(aLong -> { userExceptAuthorIds.forEach(aLong -> {
AUserInAServer user = userInServerManagementService.loadUserConditional(aLong).orElseThrow(() -> new UserInServerNotFoundException(aLong)); AUserInAServer user = userInServerManagementService.loadUserOptional(aLong).orElseThrow(() -> new UserInServerNotFoundException(aLong));
starboardPostReactorManagementService.addReactor(starboardPost, user); starboardPostReactorManagementService.addReactor(starboardPost, user);
}); });
} }
private CompletableFuture<StarboardPostModel> buildStarboardPostModel(CachedMessage message, Integer starCount) { private CompletableFuture<StarboardPostModel> buildStarboardPostModel(CachedMessage message, Integer starCount) {
return botService.getMemberInServerAsync(message.getServerId(), message.getAuthorId()).thenApply(member -> { return botService.getMemberInServerAsync(message.getServerId(), message.getAuthor().getAuthorId()).thenApply(member -> {
Optional<TextChannel> channel = botService.getTextChannelFromServerOptional(message.getServerId(), message.getChannelId()); Optional<TextChannel> channel = botService.getTextChannelFromServerOptional(message.getServerId(), message.getChannelId());
Optional<Guild> guild = botService.getGuildByIdOptional(message.getServerId()); Optional<Guild> guild = botService.getGuildByIdOptional(message.getServerId());
// TODO use model objects instead of building entity models
AChannel aChannel = AChannel.builder().id(message.getChannelId()).build(); AChannel aChannel = AChannel.builder().id(message.getChannelId()).build();
AUser user = AUser.builder().id(message.getAuthorId()).build(); AUser user = AUser.builder().id(message.getAuthor().getAuthorId()).build();
AServer server = AServer.builder().id(message.getServerId()).build(); AServer server = AServer.builder().id(message.getServerId()).build();
String starLevelEmote = getAppropriateEmote(message.getServerId(), starCount); String starLevelEmote = getAppropriateEmote(message.getServerId(), starCount);
return StarboardPostModel return StarboardPostModel

View File

@@ -44,7 +44,7 @@ public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostMa
} }
AChannel embeddingChannel = channelManagementService.loadChannel(messageContainingEmbed.getChannel().getIdLong()); AChannel embeddingChannel = channelManagementService.loadChannel(messageContainingEmbed.getChannel().getIdLong());
AChannel embeddedChannel = channelManagementService.loadChannel(embeddedMessage.getChannelId()); AChannel embeddedChannel = channelManagementService.loadChannel(embeddedMessage.getChannelId());
AUserInAServer embeddedAuthor = userInServerManagementService.loadUser(embeddedMessage.getServerId(), embeddedMessage.getAuthorId()); AUserInAServer embeddedAuthor = userInServerManagementService.loadUser(embeddedMessage.getServerId(), embeddedMessage.getAuthor().getAuthorId());
EmbeddedMessage messageEmbedPost = EmbeddedMessage EmbeddedMessage messageEmbedPost = EmbeddedMessage
.builder() .builder()
.embeddedMessageId(embeddedMessage.getMessageId()) .embeddedMessageId(embeddedMessage.getMessageId())
@@ -58,8 +58,8 @@ public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostMa
.build(); .build();
log.info("Saving embedded post: message {} by user {} in channel {} in server {} embedded message {} by user {} in channel {} in server {}.", 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(), messageContainingEmbed.getIdLong(), messageContainingEmbed.getAuthor().getIdLong(), embeddingChannel.getId(), messageContainingEmbed.getChannel().getIdLong(),
embeddedMessage.getMessageId(), embeddedMessage.getAuthorId(), embeddedMessage.getChannelId(), embeddedMessage.getServerId()); embeddedMessage.getMessageId(), embeddedMessage.getAuthor().getAuthorId(), embeddedMessage.getChannelId(), embeddedMessage.getServerId());
embeddedMessageRepository.save(messageEmbedPost); embeddedMessageRepository.save(messageEmbedPost);
} }

View File

@@ -8,7 +8,6 @@ import dev.sheldan.abstracto.utility.models.database.PostedImage;
import dev.sheldan.abstracto.utility.models.database.embed.PostIdentifier; import dev.sheldan.abstracto.utility.models.database.embed.PostIdentifier;
import dev.sheldan.abstracto.utility.repository.PostedImageRepository; import dev.sheldan.abstracto.utility.repository.PostedImageRepository;
import dev.sheldan.abstracto.utility.service.RepostServiceBean; import dev.sheldan.abstracto.utility.service.RepostServiceBean;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -25,11 +24,11 @@ public class PostedImageManagementBean implements PostedImageManagement {
private RepostCheckChannelGroupManagement checkChannelBean; private RepostCheckChannelGroupManagement checkChannelBean;
@Override @Override
public PostedImage createPost(AServerAChannelAUser creation, Message source, String hash, Integer index) { public PostedImage createPost(AServerAChannelAUser creation, Long messageId, String hash, Integer index) {
PostedImage post = PostedImage PostedImage post = PostedImage
.builder() .builder()
.imageHash(hash) .imageHash(hash)
.postId(new PostIdentifier(source.getIdLong(), index)) .postId(new PostIdentifier(messageId, index))
.poster(creation.getAUserInAServer()) .poster(creation.getAUserInAServer())
.server(creation.getGuild()) .server(creation.getGuild())
.postedChannel(creation.getChannel()) .postedChannel(creation.getChannel())

View File

@@ -1,22 +1,21 @@
package dev.sheldan.abstracto.utility.listener.embed; package dev.sheldan.abstracto.utility.listener.embed;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReactions;
import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.MessageService; import dev.sheldan.abstracto.core.service.MessageService;
import dev.sheldan.abstracto.core.test.MockUtils;
import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage; import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage;
import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService; import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService;
import 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.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.util.Optional; import java.util.Optional;
@@ -27,12 +26,11 @@ import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class MessageEmbedRemovalReactionListenerTest { public class MessageEmbedRemovalReactionListenerTest {
public static final long EMBEDDING_USER_ID = 6L;
public static final long EMBEDDED_USER_ID = 7L;
@InjectMocks @InjectMocks
private MessageEmbedRemovalReactionListener testUnit; private MessageEmbedRemovalReactionListener testUnit;
@Mock
private BotService botService;
@Mock @Mock
private MessageEmbedPostManagementService messageEmbedPostManagementService; private MessageEmbedPostManagementService messageEmbedPostManagementService;
@@ -43,99 +41,111 @@ public class MessageEmbedRemovalReactionListenerTest {
private EmoteService emoteService; private EmoteService emoteService;
@Mock @Mock
private GuildMessageReactionAddEvent messageReaction; private CachedReactions messageReaction;
@Mock @Mock
private MessageReaction.ReactionEmote reactionEmote; private CachedEmote reactionEmote;
@Mock @Mock
private Emote emote; private AUserInAServer embeddingUser;
@Mock
private AUser embeddingAUser;
@Mock
private AUserInAServer embeddedUser;
@Mock
private AUser embeddedAUser;
@Mock
private ServerUser reactingUser;
private static final Long SERVER_ID = 4L;
private static final Long CHANNEL_ID = 5L;
private static final Long MESSAGE_ID = 6L;
private static final Long USER_ID = 3L;
@Test @Test
public void testAddingWrongEmote() { public void testAddingWrongEmote() {
Long messageId = 4L; executeRemovalEmoteAddedTest(false);
executeRemovalAddedTest(false, messageId); verify(messageEmbedPostManagementService, times(0)).findEmbeddedPostByMessageId(MESSAGE_ID);
verify(messageEmbedPostManagementService, times(0)).findEmbeddedPostByMessageId(messageId);
} }
@Test @Test
public void testAddingCorrectEmoteToWrongMessage() { public void testAddingCorrectEmoteToWrongMessage() {
Long messageId = 4L; when(messageEmbedPostManagementService.findEmbeddedPostByMessageId(MESSAGE_ID)).thenReturn(Optional.empty());
when(messageEmbedPostManagementService.findEmbeddedPostByMessageId(messageId)).thenReturn(Optional.empty()); executeRemovalEmoteAddedTest(true);
executeRemovalAddedTest(true, messageId);
} }
@Test @Test
public void testIncorrectUserAddingReaction() { public void testIncorrectUserAddingReaction() {
Long serverId = 4L; when(embeddingUser.getUserReference()).thenReturn(embeddingAUser);
AServer server = MockUtils.getServer(serverId); when(embeddedUser.getUserReference()).thenReturn(embeddedAUser);
AUserInAServer embeddingUser = MockUtils.getUserObject(6L, server); when(embeddingAUser.getId()).thenReturn(USER_ID);
AUserInAServer embeddedUser = MockUtils.getUserObject(7L, server); when(embeddedAUser.getId()).thenReturn(USER_ID + 1);
executeDeletionTest(serverId, 5L, embeddingUser, embeddedUser, MockUtils.getUserObject(5L, server), 0); when(reactingUser.getUserId()).thenReturn(USER_ID + 2);
executeDeletionTest(embeddingUser, embeddedUser, reactingUser, 0);
} }
@Test @Test
public void testEmbeddedUserAddingReaction() { public void testEmbeddedUserAddingReaction() {
Long serverId = 4L; when(embeddedUser.getUserReference()).thenReturn(embeddedAUser);
AServer server = MockUtils.getServer(serverId); when(embeddedAUser.getId()).thenReturn(USER_ID + 1);
AUserInAServer embeddingUser = MockUtils.getUserObject(6L, server); when(reactingUser.getUserId()).thenReturn(USER_ID + 1);
AUserInAServer embeddedUser = MockUtils.getUserObject(7L, server); executeDeletionTest(embeddingUser, embeddedUser, reactingUser, 1);
executeDeletionTest(serverId, 4L, embeddingUser, embeddedUser, embeddedUser, 1);
} }
@Test @Test
public void testEmbeddingUserAddingReaction() { public void testEmbeddingUserAddingReaction() {
Long serverId = 4L; when(embeddingUser.getUserReference()).thenReturn(embeddingAUser);
AServer server = MockUtils.getServer(serverId); when(embeddedUser.getUserReference()).thenReturn(embeddedAUser);
AUserInAServer embeddingUser = MockUtils.getUserObject(6L, server); when(embeddingAUser.getId()).thenReturn(USER_ID);
AUserInAServer embeddedUser = MockUtils.getUserObject(7L, server); when(embeddedAUser.getId()).thenReturn(USER_ID + 1);
executeDeletionTest(serverId, 5L, embeddingUser, embeddedUser, embeddingUser, 1); when(reactingUser.getUserId()).thenReturn(USER_ID);
executeDeletionTest(embeddingUser, embeddedUser, reactingUser, 1);
} }
private void executeDeletionTest(Long serverId, Long channelId, AUserInAServer embeddingUser, AUserInAServer embeddedUser, AUserInAServer userAddingReaction, int wantedDeletions) { private void executeDeletionTest(AUserInAServer embeddingUser, AUserInAServer embeddedUser, ServerUser userAddingReaction, int wantedDeletions) {
Long messageId = 4L;
CachedMessage cachedMessage = CachedMessage CachedMessage cachedMessage = CachedMessage
.builder() .builder()
.serverId(serverId) .serverId(SERVER_ID)
.messageId(messageId) .messageId(MESSAGE_ID)
.channelId(channelId) .channelId(CHANNEL_ID)
.build(); .build();
AEmote reactedEmote = AEmote.builder().build(); AEmote reactedEmote = AEmote.builder().build();
when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote); when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, SERVER_ID)).thenReturn(reactedEmote);
when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); when(messageReaction.getEmote()).thenReturn(reactionEmote);
when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(true); when(emoteService.compareCachedEmoteWithAEmote(reactionEmote, reactedEmote)).thenReturn(true);
EmbeddedMessage message = EmbeddedMessage EmbeddedMessage message = EmbeddedMessage
.builder() .builder()
.embeddingUser(embeddingUser) .embeddingUser(embeddingUser)
.embeddedUser(embeddedUser) .embeddedUser(embeddedUser)
.build(); .build();
when(messageEmbedPostManagementService.findEmbeddedPostByMessageId(messageId)).thenReturn(Optional.of(message)); when(messageEmbedPostManagementService.findEmbeddedPostByMessageId(MESSAGE_ID)).thenReturn(Optional.of(message));
when(messageService.deleteMessageInChannelInServer(serverId, channelId, messageId)).thenReturn(CompletableFuture.completedFuture(null)); when(messageService.deleteMessageInChannelInServer(SERVER_ID, CHANNEL_ID, MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(null));
when(messageEmbedPostManagementService.findEmbeddedPostByMessageId(messageId)).thenReturn(Optional.of(message)); when(messageEmbedPostManagementService.findEmbeddedPostByMessageId(MESSAGE_ID)).thenReturn(Optional.of(message));
testUnit.executeReactionAdded(cachedMessage, messageReaction, userAddingReaction); testUnit.executeReactionAdded(cachedMessage, messageReaction, userAddingReaction);
verify(messageService, times(wantedDeletions)).deleteMessageInChannelInServer(serverId, channelId, messageId); verify(messageService, times(wantedDeletions)).deleteMessageInChannelInServer(SERVER_ID, CHANNEL_ID, MESSAGE_ID);
if(wantedDeletions > 0) { if(wantedDeletions > 0) {
verify(messageEmbedPostManagementService, times(1)).deleteEmbeddedMessage(message); verify(messageEmbedPostManagementService, times(1)).deleteEmbeddedMessage(message);
} }
} }
private void executeRemovalAddedTest(boolean wasCorrectEmote, Long messageId) { private void executeRemovalEmoteAddedTest(boolean wasCorrectEmote) {
Long serverId = 4L;
AServer server = MockUtils.getServer(serverId);
Long channelId = 5L;
CachedMessage cachedMessage = CachedMessage CachedMessage cachedMessage = CachedMessage
.builder() .builder()
.serverId(serverId) .serverId(SERVER_ID)
.messageId(messageId) .messageId(MESSAGE_ID)
.channelId(channelId) .channelId(CHANNEL_ID)
.build(); .build();
AUserInAServer userInAServer = MockUtils.getUserObject(5L, server); ServerUser serverUser = Mockito.mock(ServerUser.class);
AEmote reactedEmote = AEmote.builder().build(); AEmote reactedEmote = AEmote.builder().build();
when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote); when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, SERVER_ID)).thenReturn(reactedEmote);
when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); when(messageReaction.getEmote()).thenReturn(reactionEmote);
when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(wasCorrectEmote); when(emoteService.compareCachedEmoteWithAEmote(reactionEmote, reactedEmote)).thenReturn(wasCorrectEmote);
testUnit.executeReactionAdded(cachedMessage, messageReaction, userInAServer); testUnit.executeReactionAdded(cachedMessage, messageReaction, serverUser);
verify(messageService, times(0)).deleteMessageInChannelInServer(serverId, channelId, messageId); verify(messageService, times(0)).deleteMessageInChannelInServer(SERVER_ID, CHANNEL_ID, MESSAGE_ID);
} }
} }

View File

@@ -1,6 +1,9 @@
package dev.sheldan.abstracto.utility.listener.repost; package dev.sheldan.abstracto.utility.listener.repost;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel; import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.utility.service.RepostCheckChannelService; import dev.sheldan.abstracto.utility.service.RepostCheckChannelService;
import dev.sheldan.abstracto.utility.service.RepostService; import dev.sheldan.abstracto.utility.service.RepostService;
import dev.sheldan.abstracto.utility.service.management.PostedImageManagement; import dev.sheldan.abstracto.utility.service.management.PostedImageManagement;
@@ -33,6 +36,12 @@ public class RepostEmbedListenerTest {
@Mock @Mock
private PostedImageManagement repostManagement; private PostedImageManagement repostManagement;
@Mock
private ChannelManagementService channelManagementService;
@Mock
private BotService botService;
@Mock @Mock
private GuildMessageEmbedEventModel model; private GuildMessageEmbedEventModel model;
@@ -42,6 +51,9 @@ public class RepostEmbedListenerTest {
@Mock @Mock
private Message message; private Message message;
@Mock
private AChannel channel;
@Captor @Captor
private ArgumentCaptor<List<MessageEmbed>> embedListsParameterCaptor; private ArgumentCaptor<List<MessageEmbed>> embedListsParameterCaptor;
@@ -51,8 +63,7 @@ public class RepostEmbedListenerTest {
@Test @Test
public void testExecuteCheckDisabled() { public void testExecuteCheckDisabled() {
when(model.getChannel()).thenReturn(textChannel); when(model.getChannelId()).thenReturn(CHANNEL_ID);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(textChannel)).thenReturn(false);
testUnit.execute(model); testUnit.execute(model);
verify(repostManagement, times(0)).messageEmbedsHaveBeenCovered(anyLong()); verify(repostManagement, times(0)).messageEmbedsHaveBeenCovered(anyLong());
} }
@@ -61,11 +72,8 @@ public class RepostEmbedListenerTest {
public void testExecuteEmbedsHaveBeenCovered() { public void testExecuteEmbedsHaveBeenCovered() {
channelSetup(); channelSetup();
setupMessageHasBeenCovered(true); setupMessageHasBeenCovered(true);
Guild guild = Mockito.mock(Guild.class);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(textChannel.getGuild()).thenReturn(guild);
testUnit.execute(model); testUnit.execute(model);
verify(repostService, times(0)).processMessageEmbedsRepostCheck(any(), any()); verify(repostService, times(0)).processMessageEmbedsRepostCheck(anyList(), any(Message.class));
} }
@Test @Test
@@ -75,7 +83,7 @@ public class RepostEmbedListenerTest {
RestAction messageRestAction = Mockito.mock(RestAction.class); RestAction messageRestAction = Mockito.mock(RestAction.class);
when(textChannel.retrieveMessageById(MESSAGE_ID)).thenReturn(messageRestAction); when(textChannel.retrieveMessageById(MESSAGE_ID)).thenReturn(messageRestAction);
testUnit.execute(model); testUnit.execute(model);
verify(repostService, times(0)).processMessageEmbedsRepostCheck(any(), any()); verify(repostService, times(0)).processMessageEmbedsRepostCheck(anyList(), any(Message.class));
} }
@Test @Test
@@ -132,9 +140,11 @@ public class RepostEmbedListenerTest {
} }
private void channelSetup() { private void channelSetup() {
when(model.getChannel()).thenReturn(textChannel); when(model.getChannelId()).thenReturn(CHANNEL_ID);
when(textChannel.getIdLong()).thenReturn(CHANNEL_ID); when(model.getServerId()).thenReturn(SERVER_ID);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(textChannel)).thenReturn(true); when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(channel);
when(botService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(channel)).thenReturn(true);
} }

View File

@@ -1,11 +1,12 @@
package dev.sheldan.abstracto.utility.listener.repost; package dev.sheldan.abstracto.utility.listener.repost;
import dev.sheldan.abstracto.core.models.cache.CachedEmbed;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.utility.service.RepostCheckChannelService; import dev.sheldan.abstracto.utility.service.RepostCheckChannelService;
import dev.sheldan.abstracto.utility.service.RepostService; import dev.sheldan.abstracto.utility.service.RepostService;
import net.dv8tion.jda.api.entities.EmbedType; import net.dv8tion.jda.api.entities.EmbedType;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.TextChannel;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -26,17 +27,22 @@ public class RepostMessageReceivedListenerTest {
@Mock @Mock
private RepostCheckChannelService repostCheckChannelService; private RepostCheckChannelService repostCheckChannelService;
@Mock
private ChannelManagementService channelManagementService;
@Mock @Mock
private RepostService repostService; private RepostService repostService;
@Mock @Mock
private Message message; private CachedMessage message;
@Mock @Mock
private TextChannel textChannel; private AChannel channel;
@Captor @Captor
private ArgumentCaptor<List<MessageEmbed>> embedListCaptor; private ArgumentCaptor<List<CachedEmbed>> embedListCaptor;
private static final Long CHANNEL_ID = 4L;
@Test @Test
public void testExecuteCheckDisabled() { public void testExecuteCheckDisabled() {
@@ -57,7 +63,7 @@ public class RepostMessageReceivedListenerTest {
@Test @Test
public void testExecuteOnlyMessageOneImageAttachment() { public void testExecuteOnlyMessageOneImageAttachment() {
setupRepostCheckEnabled(true); setupRepostCheckEnabled(true);
MessageEmbed imageEmbed = Mockito.mock(MessageEmbed.class); CachedEmbed imageEmbed = Mockito.mock(CachedEmbed.class);
when(imageEmbed.getType()).thenReturn(EmbedType.IMAGE); when(imageEmbed.getType()).thenReturn(EmbedType.IMAGE);
when(message.getEmbeds()).thenReturn(Arrays.asList(imageEmbed)); when(message.getEmbeds()).thenReturn(Arrays.asList(imageEmbed));
testUnit.execute(message); testUnit.execute(message);
@@ -67,9 +73,9 @@ public class RepostMessageReceivedListenerTest {
@Test @Test
public void testExecuteOnlyMessageTwoEmbedsOneImageAttachment() { public void testExecuteOnlyMessageTwoEmbedsOneImageAttachment() {
setupRepostCheckEnabled(true); setupRepostCheckEnabled(true);
MessageEmbed imageEmbed = Mockito.mock(MessageEmbed.class); CachedEmbed imageEmbed = Mockito.mock(CachedEmbed.class);
when(imageEmbed.getType()).thenReturn(EmbedType.IMAGE); when(imageEmbed.getType()).thenReturn(EmbedType.IMAGE);
MessageEmbed nonImageEmbed = Mockito.mock(MessageEmbed.class); CachedEmbed nonImageEmbed = Mockito.mock(CachedEmbed.class);
when(nonImageEmbed.getType()).thenReturn(EmbedType.LINK); when(nonImageEmbed.getType()).thenReturn(EmbedType.LINK);
when(message.getEmbeds()).thenReturn(Arrays.asList(imageEmbed, nonImageEmbed)); when(message.getEmbeds()).thenReturn(Arrays.asList(imageEmbed, nonImageEmbed));
testUnit.execute(message); testUnit.execute(message);
@@ -77,14 +83,15 @@ public class RepostMessageReceivedListenerTest {
} }
private void setupRepostCheckEnabled(boolean b) { private void setupRepostCheckEnabled(boolean b) {
when(message.getTextChannel()).thenReturn(textChannel); when(message.getChannelId()).thenReturn(CHANNEL_ID);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(textChannel)).thenReturn(b); when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(channel);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(channel)).thenReturn(b);
} }
private void verifySingleEmbed(MessageEmbed imageEmbed) { private void verifySingleEmbed(CachedEmbed imageEmbed) {
verify(repostService, times(1)).processMessageAttachmentRepostCheck(message); verify(repostService, times(1)).processMessageAttachmentRepostCheck(message);
verify(repostService, times(1)).processMessageEmbedsRepostCheck(embedListCaptor.capture(), eq(message)); verify(repostService, times(1)).processMessageEmbedsRepostCheck(embedListCaptor.capture(), eq(message));
List<MessageEmbed> processedEmbeds = embedListCaptor.getValue(); List<CachedEmbed> processedEmbeds = embedListCaptor.getValue();
Assert.assertEquals(1, processedEmbeds.size()); Assert.assertEquals(1, processedEmbeds.size());
Assert.assertEquals(imageEmbed, processedEmbeds.get(0)); Assert.assertEquals(imageEmbed, processedEmbeds.get(0));
} }

View File

@@ -1,27 +1,24 @@
package dev.sheldan.abstracto.utility.listener.starboard; package dev.sheldan.abstracto.utility.listener.starboard;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReaction; import dev.sheldan.abstracto.core.models.cache.CachedReactions;
import dev.sheldan.abstracto.core.models.database.AConfig; import dev.sheldan.abstracto.core.models.database.*;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService; import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.test.MockUtils;
import dev.sheldan.abstracto.utility.models.database.StarboardPost; import dev.sheldan.abstracto.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.service.StarboardService; import dev.sheldan.abstracto.utility.service.StarboardService;
import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService; import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService;
import dev.sheldan.abstracto.utility.service.management.StarboardPostReactorManagementService; import dev.sheldan.abstracto.utility.service.management.StarboardPostReactorManagementService;
import net.dv8tion.jda.api.entities.MessageReaction; import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList; import java.util.ArrayList;
@@ -29,6 +26,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import static dev.sheldan.abstracto.utility.listener.starboard.StarboardListener.STAR_EMOTE;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
@@ -37,9 +35,6 @@ public class StarboardListenerTest {
@InjectMocks @InjectMocks
private StarboardListener testUnit; private StarboardListener testUnit;
@Mock
private BotService botService;
@Mock @Mock
private ConfigManagementService configManagementService; private ConfigManagementService configManagementService;
@@ -59,49 +54,74 @@ public class StarboardListenerTest {
private EmoteService emoteService; private EmoteService emoteService;
@Mock @Mock
private GuildMessageReactionAddEvent addEvent; private CachedReactions cachedReaction;
@Mock
private GuildMessageReactionRemoveEvent removeEvent;
@Mock @Mock
private MessageReaction.ReactionEmote reactionEmote; private MessageReaction.ReactionEmote reactionEmote;
@Mock
private CachedMessage cachedMessage;
@Mock
private ServerUser serverUserActing;
@Mock
private CachedAuthor cachedAuthor;
@Mock
private AUserInAServer userInServerActing;
@Mock
private AUser userActing;
@Mock
private AUserInAServer userInAServer;
@Mock
private AUser aUser;
@Mock
private AServer server;
@Mock
private StarboardPost post;
@Mock
private CachedEmote cachedEmote;
@Mock
private AEmote starEmote;
private static final Long MESSAGE_ID = 5L;
private static final Long SERVER_ID = 6L;
private static final Long AUTHOR_ID = 4L;
private static final Long USER_ACTING_ID = 7L;
@Test @Test
public void testAuthorAddingStar() { public void testAuthorAddingStar() {
Long serverId = 5L; when(cachedAuthor.getAuthorId()).thenReturn(AUTHOR_ID);
Long authorId = 4L; when(cachedMessage.getAuthor()).thenReturn(cachedAuthor);
CachedMessage cachedMessage = CachedMessage when(serverUserActing.getUserId()).thenReturn(AUTHOR_ID);
.builder() testUnit.executeReactionAdded(cachedMessage, cachedReaction, serverUserActing);
.authorId(authorId) verify(emoteService, times(0)).getEmoteOrDefaultEmote(STAR_EMOTE, SERVER_ID);
.serverId(serverId)
.build();
AUserInAServer userAdding = MockUtils.getUserObject(authorId, MockUtils.getServer(serverId));
testUnit.executeReactionAdded(cachedMessage, addEvent, userAdding);
verify(emoteService, times(0)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId);
} }
@Test @Test
public void testAddingWrongEmote() { public void testAddingWrongEmote() {
Long serverId = 5L; when(serverUserActing.getUserId()).thenReturn(USER_ACTING_ID);
Long authorId = 4L; setupWrongEmote(SERVER_ID, AUTHOR_ID, starEmote);
Long reactionUserId = 7L; when(cachedReaction.getEmote()).thenReturn(cachedEmote);
AEmote starEmote = AEmote.builder().build(); when(emoteService.compareCachedEmoteWithAEmote(cachedEmote, starEmote)).thenReturn(false);
AUserInAServer userAdding = MockUtils.getUserObject(reactionUserId, MockUtils.getServer(serverId)); testUnit.executeReactionAdded(cachedMessage, cachedReaction, serverUserActing);
CachedMessage cachedMessage = setupWrongEmote(serverId, authorId, starEmote); verify(emoteService, times(1)).getEmoteOrDefaultEmote(STAR_EMOTE, SERVER_ID);
testUnit.executeReactionAdded(cachedMessage, addEvent, userAdding);
verify(emoteService, times(1)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId);
verify(emoteService, times(0)).getReactionFromMessageByEmote(any(CachedMessage.class), eq(starEmote)); verify(emoteService, times(0)).getReactionFromMessageByEmote(any(CachedMessage.class), eq(starEmote));
} }
@Test @Test
public void testAddingEmoteToExistingPostButNowBelowThreshold() { public void testAddingEmoteToExistingPostButNowBelowThreshold() {
Long requiredStars = 5L; Long requiredStars = 5L;
AServer server = MockUtils.getServer(); setupActingAndAuthor();
AUserInAServer userAdding = MockUtils.getUserObject(7L, server); executeAddingTest(requiredStars, post);
AUserInAServer author = MockUtils.getUserObject(8L, server);
StarboardPost post = StarboardPost.builder().build();
executeAddingTest(userAdding, author, requiredStars, post);
verify(starboardService, times(1)).deleteStarboardMessagePost(post); verify(starboardService, times(1)).deleteStarboardMessagePost(post);
verify(starboardPostManagementService, times(1)).removePost(post); verify(starboardPostManagementService, times(1)).removePost(post);
} }
@@ -109,10 +129,8 @@ public class StarboardListenerTest {
@Test @Test
public void testAddingEmoteBelowThreshold() { public void testAddingEmoteBelowThreshold() {
Long requiredStars = 5L; Long requiredStars = 5L;
AServer server = MockUtils.getServer(); setupActingAndAuthor();
AUserInAServer userAdding = MockUtils.getUserObject(7L, server); executeAddingTest(requiredStars, null);
AUserInAServer author = MockUtils.getUserObject(8L, server);
executeAddingTest(userAdding, author, requiredStars, null);
verify(starboardService, times(0)).deleteStarboardMessagePost(any(StarboardPost.class)); verify(starboardService, times(0)).deleteStarboardMessagePost(any(StarboardPost.class));
verify(starboardPostManagementService, times(0)).removePost(any(StarboardPost.class)); verify(starboardPostManagementService, times(0)).removePost(any(StarboardPost.class));
} }
@@ -120,61 +138,44 @@ public class StarboardListenerTest {
@Test @Test
public void testAddingEmoteReachingThreshold() { public void testAddingEmoteReachingThreshold() {
Long requiredStars = 1L; Long requiredStars = 1L;
AServer server = MockUtils.getServer(); setupActingAndAuthor();
AUserInAServer userAdding = MockUtils.getUserObject(7L, server); executeAddingTest(requiredStars, null);
AUserInAServer author = MockUtils.getUserObject(8L, server); verify(starboardService, times(1)).createStarboardPost(any(CachedMessage.class), anyList(), eq(userInServerActing), eq(userInAServer));
executeAddingTest(userAdding, author, requiredStars, null);
verify(starboardService, times(1)).createStarboardPost(any(CachedMessage.class), anyList(), eq(userAdding), eq(author));
} }
@Test @Test
public void testAddingEmoteToExistingPost() { public void testAddingEmoteToExistingPost() {
Long requiredStars = 1L; Long requiredStars = 1L;
AServer server = MockUtils.getServer(); setupActingAndAuthor();
AUserInAServer userAdding = MockUtils.getUserObject(7L, server); executeAddingTest(requiredStars, post);
AUserInAServer author = MockUtils.getUserObject(8L, server);
StarboardPost post = StarboardPost.builder().build();
executeAddingTest(userAdding, author, requiredStars, post);
verify(starboardService, times(1)).updateStarboardPost(eq(post), any(CachedMessage.class), anyList()); verify(starboardService, times(1)).updateStarboardPost(eq(post), any(CachedMessage.class), anyList());
verify(starboardPostReactorManagementService, times(1)).addReactor(post, userAdding); verify(starboardPostReactorManagementService, times(1)).addReactor(post, userInServerActing);
} }
@Test @Test
public void testAuthorRemovingReaction() { public void testAuthorRemovingReaction() {
Long serverId = 5L; when(cachedAuthor.getAuthorId()).thenReturn(AUTHOR_ID);
Long authorId = 4L; when(cachedMessage.getAuthor()).thenReturn(cachedAuthor);
CachedMessage cachedMessage = CachedMessage when(serverUserActing.getUserId()).thenReturn(AUTHOR_ID);
.builder() testUnit.executeReactionRemoved(cachedMessage, cachedReaction, serverUserActing);
.authorId(authorId) verify(emoteService, times(0)).getEmoteOrDefaultEmote(STAR_EMOTE, SERVER_ID);
.serverId(serverId)
.build();
AUserInAServer userAdding = MockUtils.getUserObject(authorId, MockUtils.getServer(serverId));
testUnit.executeReactionRemoved(cachedMessage, removeEvent, userAdding);
verify(emoteService, times(0)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId);
} }
@Test @Test
public void testRemovingWrongEmote() { public void testRemovingWrongEmote() {
Long serverId = 5L; when(serverUserActing.getUserId()).thenReturn(USER_ACTING_ID);
Long authorId = 4L; setupWrongEmote(SERVER_ID, AUTHOR_ID, starEmote);
Long reactionUserId = 7L; testUnit.executeReactionRemoved(cachedMessage, cachedReaction, serverUserActing);
AEmote starEmote = AEmote.builder().build(); verify(emoteService, times(1)).getEmoteOrDefaultEmote(STAR_EMOTE, SERVER_ID);
AUserInAServer userAdding = MockUtils.getUserObject(reactionUserId, MockUtils.getServer(serverId));
CachedMessage cachedMessage = setupWrongEmote(serverId, authorId, starEmote);
testUnit.executeReactionRemoved(cachedMessage, removeEvent, userAdding);
verify(emoteService, times(1)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId);
verify(emoteService, times(0)).getReactionFromMessageByEmote(any(CachedMessage.class), eq(starEmote)); verify(emoteService, times(0)).getReactionFromMessageByEmote(any(CachedMessage.class), eq(starEmote));
} }
@Test @Test
public void testRemoveReactionFromExistingPostBelowThreshold() { public void testRemoveReactionFromExistingPostBelowThreshold() {
Long requiredStars = 5L; Long requiredStars = 5L;
AServer server = MockUtils.getServer(); List<ServerUser> remainingUsers = Arrays.asList(serverUserActing);
AUserInAServer userRemoving = MockUtils.getUserObject(7L, server); setupActingAndAuthor();
List<Long> remainingUsers = Arrays.asList(userRemoving.getUserReference().getId()); executeRemovalTest(requiredStars, remainingUsers);
AUserInAServer author = MockUtils.getUserObject(8L, server);
StarboardPost post = StarboardPost.builder().build();
executeRemovalTest(requiredStars, userRemoving, remainingUsers, userRemoving, author, post);
verify(starboardService, times(1)).deleteStarboardMessagePost(eq(post)); verify(starboardService, times(1)).deleteStarboardMessagePost(eq(post));
verify(starboardPostManagementService, times(1)).removePost(eq(post)); verify(starboardPostManagementService, times(1)).removePost(eq(post));
} }
@@ -182,13 +183,10 @@ public class StarboardListenerTest {
@Test @Test
public void testRemoveReactionFromExistingPostAboveThreshold() { public void testRemoveReactionFromExistingPostAboveThreshold() {
Long requiredStars = 0L; Long requiredStars = 0L;
AServer server = MockUtils.getServer(); List<ServerUser> remainingUsers = Arrays.asList(serverUserActing);
AUserInAServer remainingUser = MockUtils.getUserObject(9L, server); setupActingAndAuthor();
List<Long> remainingUsers = Arrays.asList(remainingUser.getUserReference().getId()); when(userInServerManagementService.loadUser(serverUserActing)).thenReturn(userInServerActing);
AUserInAServer userRemoving = MockUtils.getUserObject(7L, server); executeRemovalTest(requiredStars, remainingUsers);
AUserInAServer author = MockUtils.getUserObject(8L, server);
StarboardPost post = StarboardPost.builder().build();
executeRemovalTest(requiredStars, remainingUser, remainingUsers, userRemoving, author, post);
verify(starboardService, times(0)).deleteStarboardMessagePost(eq(post)); verify(starboardService, times(0)).deleteStarboardMessagePost(eq(post));
verify(starboardPostManagementService, times(0)).removePost(eq(post)); verify(starboardPostManagementService, times(0)).removePost(eq(post));
} }
@@ -196,12 +194,9 @@ public class StarboardListenerTest {
@Test @Test
public void testRemoveReactionFromExistingPostTriggeringThreshold() { public void testRemoveReactionFromExistingPostTriggeringThreshold() {
Long requiredStars = 1L; Long requiredStars = 1L;
AServer server = MockUtils.getServer(); ArrayList<ServerUser> usersRemaining = new ArrayList<>();
ArrayList<Long> usersRemaining = new ArrayList<>(); setupActingAndAuthor();
AUserInAServer userRemoving = MockUtils.getUserObject(7L, server); executeRemovalTest(requiredStars, usersRemaining);
AUserInAServer author = MockUtils.getUserObject(8L, server);
StarboardPost post = StarboardPost.builder().build();
executeRemovalTest(requiredStars, userRemoving, usersRemaining, userRemoving, author, post);
verify(starboardService, times(1)).deleteStarboardMessagePost(eq(post)); verify(starboardService, times(1)).deleteStarboardMessagePost(eq(post));
verify(starboardPostManagementService, times(1)).removePost(eq(post)); verify(starboardPostManagementService, times(1)).removePost(eq(post));
} }
@@ -216,13 +211,19 @@ public class StarboardListenerTest {
executeClearingTest(null); executeClearingTest(null);
} }
private void setupActingAndAuthor() {
when(userInServerActing.getUserReference()).thenReturn(userActing);
when(userActing.getId()).thenReturn(USER_ACTING_ID);
when(userInAServer.getServerReference()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
when(userInAServer.getUserReference()).thenReturn(aUser);
when(aUser.getId()).thenReturn(AUTHOR_ID);
}
private void executeClearingTest(StarboardPost post) { private void executeClearingTest(StarboardPost post) {
Long messageId = 5L; when(cachedMessage.getMessageId()).thenReturn(MESSAGE_ID);
CachedMessage cachedMessage = CachedMessage when(starboardPostManagementService.findByMessageId(MESSAGE_ID)).thenReturn(Optional.ofNullable(post));
.builder()
.messageId(messageId)
.build();
when(starboardPostManagementService.findByMessageId(messageId)).thenReturn(Optional.ofNullable(post));
testUnit.executeReactionCleared(cachedMessage); testUnit.executeReactionCleared(cachedMessage);
int callCount = post != null ? 1 : 0; int callCount = post != null ? 1 : 0;
verify(starboardPostReactorManagementService, times(callCount)).removeReactors(post); verify(starboardPostReactorManagementService, times(callCount)).removeReactors(post);
@@ -231,63 +232,60 @@ public class StarboardListenerTest {
} }
private void executeRemovalTest(Long requiredStars, AUserInAServer remainingUser, List<Long> remainingUsers, AUserInAServer userRemoving, AUserInAServer author, StarboardPost post) { private void executeRemovalTest(Long requiredStars, List<ServerUser> remainingUsers) {
Long messageId = 6L; when(cachedMessage.getServerId()).thenReturn(SERVER_ID);
Long serverId = userRemoving.getServerReference().getId(); when(cachedMessage.getMessageId()).thenReturn(MESSAGE_ID);
CachedMessage cachedMessage = CachedMessage when(cachedAuthor.getAuthorId()).thenReturn(AUTHOR_ID);
.builder() when(cachedMessage.getAuthor()).thenReturn(cachedAuthor);
.authorId(author.getUserReference().getId()) when(cachedReaction.getEmote()).thenReturn(cachedEmote);
.serverId(serverId) when(emoteService.compareCachedEmoteWithAEmote(cachedEmote, starEmote)).thenReturn(true);
.messageId(messageId) when(emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, SERVER_ID)).thenReturn(starEmote);
.build(); CachedReactions reaction = Mockito.mock(CachedReactions.class);
when(removeEvent.getReactionEmote()).thenReturn(reactionEmote); when(reaction.getUsers()).thenReturn(remainingUsers);
AEmote starEmote = AEmote.builder().build();
when(emoteService.getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote);
when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote)).thenReturn(true);
CachedReaction reaction = CachedReaction.builder().userInServersIds(remainingUsers).build();
when(emoteService.getReactionFromMessageByEmote(cachedMessage, starEmote)).thenReturn(Optional.of(reaction)); when(emoteService.getReactionFromMessageByEmote(cachedMessage, starEmote)).thenReturn(Optional.of(reaction));
when(starboardPostManagementService.findByMessageId(messageId)).thenReturn(Optional.ofNullable(post)); when(starboardPostManagementService.findByMessageId(MESSAGE_ID)).thenReturn(Optional.ofNullable(post));
when(userInServerManagementService.loadUser(serverId, author.getUserReference().getId())).thenReturn(author); when(userInServerManagementService.loadUser(SERVER_ID, AUTHOR_ID)).thenReturn(userInAServer);
when(userInServerManagementService.loadUserConditional(remainingUser.getUserReference().getId())).thenReturn(Optional.of(remainingUser)); when(serverUserActing.getUserId()).thenReturn(USER_ACTING_ID);
when(configManagementService.loadConfig(serverId, StarboardListener.FIRST_LEVEL_THRESHOLD_KEY)).thenReturn(AConfig.builder().longValue(requiredStars).build()); when(serverUserActing.getServerId()).thenReturn(SERVER_ID);
testUnit.executeReactionRemoved(cachedMessage, removeEvent, userRemoving); if(!remainingUsers.isEmpty()) {
verify(emoteService, times(1)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId); when(userInServerManagementService.loadUserOptional(SERVER_ID, USER_ACTING_ID)).thenReturn(Optional.of(userInServerActing));
}
when(configManagementService.loadConfig(SERVER_ID, StarboardListener.FIRST_LEVEL_THRESHOLD_KEY)).thenReturn(AConfig.builder().longValue(requiredStars).build());
testUnit.executeReactionRemoved(cachedMessage, cachedReaction, serverUserActing);
verify(emoteService, times(1)).getEmoteOrDefaultEmote(STAR_EMOTE, SERVER_ID);
verify(emoteService, times(1)).getReactionFromMessageByEmote(cachedMessage, starEmote); verify(emoteService, times(1)).getReactionFromMessageByEmote(cachedMessage, starEmote);
} }
private void executeAddingTest(AUserInAServer userAdding, AUserInAServer author, Long requiredStars, StarboardPost existingPost) { private void executeAddingTest(Long requiredStars, StarboardPost postToUse) {
Long messageId = 6L; when(cachedMessage.getServerId()).thenReturn(SERVER_ID);
Long serverId = userAdding.getServerReference().getId(); when(cachedMessage.getMessageId()).thenReturn(MESSAGE_ID);
CachedMessage cachedMessage = CachedMessage when(cachedAuthor.getAuthorId()).thenReturn(AUTHOR_ID);
.builder() when(cachedMessage.getAuthor()).thenReturn(cachedAuthor);
.authorId(author.getUserReference().getId()) when(cachedReaction.getEmote()).thenReturn(cachedEmote);
.serverId(serverId) when(emoteService.compareCachedEmoteWithAEmote(cachedEmote, starEmote)).thenReturn(true);
.messageId(messageId) when(emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, SERVER_ID)).thenReturn(starEmote);
.build(); CachedReactions reaction = Mockito.mock(CachedReactions.class);
when(addEvent.getReactionEmote()).thenReturn(reactionEmote); when(serverUserActing.getUserId()).thenReturn(USER_ACTING_ID);
AEmote starEmote = AEmote.builder().build(); when(serverUserActing.getServerId()).thenReturn(SERVER_ID);
when(emoteService.getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote); when(reaction.getUsers()).thenReturn(Arrays.asList(serverUserActing));
when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote)).thenReturn(true);
CachedReaction reaction = CachedReaction.builder().userInServersIds(Arrays.asList(userAdding.getUserReference().getId())).build();
when(emoteService.getReactionFromMessageByEmote(cachedMessage, starEmote)).thenReturn(Optional.of(reaction)); when(emoteService.getReactionFromMessageByEmote(cachedMessage, starEmote)).thenReturn(Optional.of(reaction));
when(starboardPostManagementService.findByMessageId(messageId)).thenReturn(Optional.ofNullable(existingPost)); when(starboardPostManagementService.findByMessageId(MESSAGE_ID)).thenReturn(Optional.ofNullable(postToUse));
when(userInServerManagementService.loadUser(serverId, author.getUserReference().getId())).thenReturn(author); when(userInServerManagementService.loadUser(SERVER_ID, AUTHOR_ID)).thenReturn(userInAServer);
when(userInServerManagementService.loadUserConditional(userAdding.getUserReference().getId())).thenReturn(Optional.of(userAdding)); when(userInServerManagementService.loadUser(serverUserActing)).thenReturn(userInServerActing);
when(configManagementService.loadConfig(serverId, StarboardListener.FIRST_LEVEL_THRESHOLD_KEY)).thenReturn(AConfig.builder().longValue(requiredStars).build()); when(userInServerManagementService.loadUserOptional(SERVER_ID, USER_ACTING_ID)).thenReturn(Optional.of(userInServerActing));
testUnit.executeReactionAdded(cachedMessage, addEvent, userAdding); AConfig starRequirementConfig = Mockito.mock(AConfig.class);
verify(emoteService, times(1)).getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId); when(starRequirementConfig.getLongValue()).thenReturn(requiredStars);
when(configManagementService.loadConfig(SERVER_ID, StarboardListener.FIRST_LEVEL_THRESHOLD_KEY)).thenReturn(starRequirementConfig);
testUnit.executeReactionAdded(cachedMessage, cachedReaction, serverUserActing);
verify(emoteService, times(1)).getEmoteOrDefaultEmote(STAR_EMOTE, SERVER_ID);
verify(emoteService, times(1)).getReactionFromMessageByEmote(cachedMessage, starEmote); verify(emoteService, times(1)).getReactionFromMessageByEmote(cachedMessage, starEmote);
} }
private CachedMessage setupWrongEmote(Long serverId, Long authorId, AEmote starEmote) { private void setupWrongEmote(Long serverId, Long authorId, AEmote starEmote) {
CachedMessage cachedMessage = CachedMessage when(cachedMessage.getServerId()).thenReturn(serverId);
.builder() when(cachedAuthor.getAuthorId()).thenReturn(authorId);
.authorId(authorId) when(cachedMessage.getAuthor()).thenReturn(cachedAuthor);
.serverId(serverId) when(cachedReaction.getEmote()).thenReturn(cachedEmote);
.build(); when(emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, serverId)).thenReturn(starEmote);
when(addEvent.getReactionEmote()).thenReturn(reactionEmote);
when(emoteService.getEmoteOrDefaultEmote(StarboardListener.STAR_EMOTE, serverId)).thenReturn(starEmote);
when(emoteService.isReactionEmoteAEmote(reactionEmote, starEmote)).thenReturn(false);
return cachedMessage;
} }
} }

View File

@@ -1,12 +1,7 @@
package dev.sheldan.abstracto.utility.listener.starboard; package dev.sheldan.abstracto.utility.listener.starboard;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.GuildChannelMember;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.test.MockUtils;
import dev.sheldan.abstracto.utility.models.database.StarboardPost; import dev.sheldan.abstracto.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService; import dev.sheldan.abstracto.utility.service.management.StarboardPostManagementService;
import org.junit.Test; import org.junit.Test;
@@ -33,31 +28,26 @@ public class StarboardPostDeletedListenerTest {
public void deleteNonStarboardPost() { public void deleteNonStarboardPost() {
Long messageId = 4L; Long messageId = 4L;
when(starboardPostManagementService.findByStarboardPostId(messageId)).thenReturn(Optional.empty()); when(starboardPostManagementService.findByStarboardPostId(messageId)).thenReturn(Optional.empty());
CachedMessage cachedMessage = CachedMessage CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
.builder() when(cachedMessage.getMessageId()).thenReturn(messageId);
.messageId(messageId) testUnit.execute(cachedMessage);
.build();
AServerAChannelAUser user = Mockito.mock(AServerAChannelAUser.class);
GuildChannelMember member = Mockito.mock(GuildChannelMember.class);
testUnit.execute(cachedMessage, user, member);
verify( starboardPostManagementService, times(0)).setStarboardPostIgnored(messageId, true); verify( starboardPostManagementService, times(0)).setStarboardPostIgnored(messageId, true);
} }
@Test @Test
public void deleteStarboardPost() { public void deleteStarboardPost() {
Long messageId = 4L; Long messageId = 4L;
AServer server = MockUtils.getServer(); Long postMessageId = 5L;
AUserInAServer author = MockUtils.getUserObject(4L, server); Long serverId = 3L;
AChannel sourceChannel = MockUtils.getTextChannel(server, 6L); AChannel sourceChannel = Mockito.mock(AChannel.class);
StarboardPost post = StarboardPost.builder().author(author).postMessageId(5L).sourceChanel(sourceChannel).build(); StarboardPost post = Mockito.mock(StarboardPost.class);
when(post.getSourceChanel()) .thenReturn(sourceChannel);
when(post.getPostMessageId()).thenReturn(postMessageId);
when(starboardPostManagementService.findByStarboardPostId(messageId)).thenReturn(Optional.of(post)); when(starboardPostManagementService.findByStarboardPostId(messageId)).thenReturn(Optional.of(post));
CachedMessage cachedMessage = CachedMessage CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
.builder() when(cachedMessage.getServerId()).thenReturn(serverId);
.messageId(messageId) when(cachedMessage.getMessageId()).thenReturn(messageId);
.build(); testUnit.execute(cachedMessage);
AServerAChannelAUser user = Mockito.mock(AServerAChannelAUser.class);
GuildChannelMember member = Mockito.mock(GuildChannelMember.class);
testUnit.execute(cachedMessage, user, member);
verify( starboardPostManagementService, times(1)).setStarboardPostIgnored(messageId, true); verify( starboardPostManagementService, times(1)).setStarboardPostIgnored(messageId, true);
} }

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.utility.service; package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.template.listener.MessageEmbeddedModel; import dev.sheldan.abstracto.core.models.template.listener.MessageEmbeddedModel;
@@ -80,6 +81,7 @@ public class MessageEmbedServiceBeanTest {
private static final Long EMBEDDING_USER_IN_SERVER_ID = 8L; private static final Long EMBEDDING_USER_IN_SERVER_ID = 8L;
private static final Long SERVER_ID = 8L; private static final Long SERVER_ID = 8L;
private static final Long CHANNEL_ID = 10L;
private static final Long USER_ID = 9L; private static final Long USER_ID = 9L;
@Mock @Mock
@@ -145,11 +147,10 @@ public class MessageEmbedServiceBeanTest {
public void testEmbedSingularLink() { public void testEmbedSingularLink() {
List<MessageEmbedLink> linksToEmbed = new ArrayList<>(); List<MessageEmbedLink> linksToEmbed = new ArrayList<>();
Long channelId = 6L; Long channelId = 6L;
Long serverId = 4L;
Long firstMessageId = 6L; Long firstMessageId = 6L;
linksToEmbed.add(MessageEmbedLink.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build()); linksToEmbed.add(MessageEmbedLink.builder().serverId(SERVER_ID).channelId(channelId).messageId(firstMessageId).build());
CachedMessage firstCachedMessage = CachedMessage.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build(); CachedMessage firstCachedMessage = CachedMessage.builder().serverId(SERVER_ID).channelId(channelId).messageId(firstMessageId).build();
when(messageCache.getMessageFromCache(serverId,channelId, firstMessageId)).thenReturn(CompletableFuture.completedFuture(firstCachedMessage)); when(messageCache.getMessageFromCache(SERVER_ID,channelId, firstMessageId)).thenReturn(CompletableFuture.completedFuture(firstCachedMessage));
Long embeddingUserId = 5L; Long embeddingUserId = 5L;
testUnit.embedLinks(linksToEmbed, textChannel, embeddingUserId, embeddingMessage); testUnit.embedLinks(linksToEmbed, textChannel, embeddingUserId, embeddingMessage);
verify( self, times(1)).embedLink(eq(firstCachedMessage), eq(textChannel), eq(embeddingUserId) , eq(embeddingMessage)); verify( self, times(1)).embedLink(eq(firstCachedMessage), eq(textChannel), eq(embeddingUserId) , eq(embeddingMessage));
@@ -158,16 +159,16 @@ public class MessageEmbedServiceBeanTest {
@Test @Test
public void testEmbedMultipleLinks() { public void testEmbedMultipleLinks() {
List<MessageEmbedLink> linksToEmbed = new ArrayList<>(); List<MessageEmbedLink> linksToEmbed = new ArrayList<>();
Long channelId = 6L;
Long serverId = 4L;
Long firstMessageId = 6L; Long firstMessageId = 6L;
Long secondMessageId = 7L; Long secondMessageId = 7L;
linksToEmbed.add(MessageEmbedLink.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build()); MessageEmbedLink messageEmbedLink = mockMessageEmbedLink(firstMessageId);
linksToEmbed.add(MessageEmbedLink.builder().serverId(serverId).channelId(channelId).messageId(secondMessageId).build()); linksToEmbed.add(messageEmbedLink);
CachedMessage firstCachedMessage = CachedMessage.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build(); MessageEmbedLink secondMessageEmbedLink = mockMessageEmbedLink(secondMessageId);
CachedMessage secondCacheMessage = CachedMessage.builder().serverId(serverId).channelId(channelId).messageId(secondMessageId).build(); linksToEmbed.add(secondMessageEmbedLink);
when(messageCache.getMessageFromCache(serverId,channelId, firstMessageId)).thenReturn(CompletableFuture.completedFuture(firstCachedMessage)); CachedMessage firstCachedMessage = mockCachedMessage(firstMessageId);
when(messageCache.getMessageFromCache(serverId,channelId, secondMessageId)).thenReturn(CompletableFuture.completedFuture(secondCacheMessage)); CachedMessage secondCacheMessage = mockCachedMessage(secondMessageId);
when(messageCache.getMessageFromCache(SERVER_ID,CHANNEL_ID, firstMessageId)).thenReturn(CompletableFuture.completedFuture(firstCachedMessage));
when(messageCache.getMessageFromCache(SERVER_ID,CHANNEL_ID, secondMessageId)).thenReturn(CompletableFuture.completedFuture(secondCacheMessage));
Long embeddingUserId = 5L; Long embeddingUserId = 5L;
testUnit.embedLinks(linksToEmbed, textChannel, embeddingUserId, embeddingMessage); testUnit.embedLinks(linksToEmbed, textChannel, embeddingUserId, embeddingMessage);
verify( self, times(2)).embedLink(cachedMessageArgumentCaptor.capture(), eq(textChannel), eq(embeddingUserId) , eq(embeddingMessage)); verify( self, times(2)).embedLink(cachedMessageArgumentCaptor.capture(), eq(textChannel), eq(embeddingUserId) , eq(embeddingMessage));
@@ -175,37 +176,54 @@ public class MessageEmbedServiceBeanTest {
List<CachedMessage> cachedMessages = cachedMessageArgumentCaptor.getAllValues(); List<CachedMessage> cachedMessages = cachedMessageArgumentCaptor.getAllValues();
Assert.assertEquals(2, cachedMessages.size()); Assert.assertEquals(2, cachedMessages.size());
CachedMessage firstEmbeddedMessage = cachedMessages.get(0); CachedMessage firstEmbeddedMessage = cachedMessages.get(0);
Assert.assertEquals(serverId, firstEmbeddedMessage.getServerId()); Assert.assertEquals(SERVER_ID, firstEmbeddedMessage.getServerId());
Assert.assertEquals(channelId, firstEmbeddedMessage.getChannelId()); Assert.assertEquals(CHANNEL_ID, firstEmbeddedMessage.getChannelId());
Assert.assertEquals(firstMessageId, firstEmbeddedMessage.getMessageId()); Assert.assertEquals(firstMessageId, firstEmbeddedMessage.getMessageId());
CachedMessage secondEmbeddedMessage = cachedMessages.get(1); CachedMessage secondEmbeddedMessage = cachedMessages.get(1);
Assert.assertEquals(serverId, secondEmbeddedMessage.getServerId()); Assert.assertEquals(SERVER_ID, secondEmbeddedMessage.getServerId());
Assert.assertEquals(channelId, secondEmbeddedMessage.getChannelId()); Assert.assertEquals(CHANNEL_ID, secondEmbeddedMessage.getChannelId());
Assert.assertEquals(secondMessageId, secondEmbeddedMessage.getMessageId()); Assert.assertEquals(secondMessageId, secondEmbeddedMessage.getMessageId());
} }
private MessageEmbedLink mockMessageEmbedLink(Long messageId) {
MessageEmbedLink secondMessageEmbedLink = Mockito.mock(MessageEmbedLink.class);
when(secondMessageEmbedLink.getServerId()).thenReturn(SERVER_ID);
when(secondMessageEmbedLink.getChannelId()).thenReturn(CHANNEL_ID);
when(secondMessageEmbedLink.getMessageId()).thenReturn(messageId);
return secondMessageEmbedLink;
}
private CachedMessage mockCachedMessage(Long secondMessageId) {
CachedMessage secondCacheMessage = Mockito.mock(CachedMessage.class);
when(secondCacheMessage.getServerId()).thenReturn(SERVER_ID);
when(secondCacheMessage.getChannelId()).thenReturn(CHANNEL_ID);
when(secondCacheMessage.getMessageId()).thenReturn(secondMessageId);
return secondCacheMessage;
}
@Test @Test
public void testLoadingEmbeddingModel() { public void testLoadingEmbeddingModel() {
CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
when(cachedMessage.getServerId()).thenReturn(SERVER_ID); when(cachedMessage.getServerId()).thenReturn(SERVER_ID);
when(cachedMessage.getAuthorId()).thenReturn(USER_ID); CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
when(userInServerManagementService.loadUserConditional(EMBEDDING_USER_IN_SERVER_ID)).thenReturn(Optional.of(embeddingUser)); when(cachedAuthor.getAuthorId()).thenReturn(USER_ID);
when(cachedMessage.getAuthor()).thenReturn(cachedAuthor);
when(userInServerManagementService.loadUserOptional(EMBEDDING_USER_IN_SERVER_ID)).thenReturn(Optional.of(embeddingUser));
when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(embeddingMember)); when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(embeddingMember));
MessageEmbeddedModel model = Mockito.mock(MessageEmbeddedModel.class); MessageEmbeddedModel model = Mockito.mock(MessageEmbeddedModel.class);
when(self.loadMessageEmbedModel(embeddingMessage, cachedMessage, embeddingMember)).thenReturn(model); when(self.loadMessageEmbedModel(embeddingMessage, cachedMessage, embeddingMember)).thenReturn(model);
when(self.sendEmbeddingMessage(cachedMessage, textChannel, EMBEDDING_USER_IN_SERVER_ID, model)).thenReturn(CompletableFuture.completedFuture(null)); when(self.sendEmbeddingMessage(cachedMessage, textChannel, EMBEDDING_USER_IN_SERVER_ID, model)).thenReturn(CompletableFuture.completedFuture(null));
testUnit.embedLink(cachedMessage, textChannel, EMBEDDING_USER_IN_SERVER_ID, embeddingMessage).join(); CompletableFuture<Void> embedFuture = testUnit.embedLink(cachedMessage, textChannel, EMBEDDING_USER_IN_SERVER_ID, embeddingMessage);
Assert.assertTrue(embedFuture.isDone());
} }
@Test @Test
public void testNotFoundUserEmbeddingLink() { public void testNotFoundUserEmbeddingLink() {
Long channelId = 6L;
Long serverId = 4L;
Long firstMessageId = 6L; Long firstMessageId = 6L;
CachedMessage cachedMessage = CachedMessage.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build(); CachedMessage cachedMessage = mockCachedMessage(firstMessageId);
Long userEmbeddingUserInServerId = 5L; Long userEmbeddingUserInServerId = 5L;
when(userInServerManagementService.loadUserConditional(userEmbeddingUserInServerId)).thenReturn(Optional.empty()); when(userInServerManagementService.loadUserOptional(userEmbeddingUserInServerId)).thenReturn(Optional.empty());
testUnit.embedLink(cachedMessage, textChannel, userEmbeddingUserInServerId, embeddingMessage); testUnit.embedLink(cachedMessage, textChannel, userEmbeddingUserInServerId, embeddingMessage);
} }

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.utility.service; package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser; import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.cache.*;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUser;
@@ -107,16 +108,10 @@ public class RepostServiceBeanTest {
private Repost repost; private Repost repost;
@Mock @Mock
private Message message; private CachedMessage message;
@Mock @Mock
private TextChannel textChannel; private CachedAuthor author;
@Mock
private Member member;
@Mock
private User jdaUser;
private static final Long SERVER_ID = 4L; private static final Long SERVER_ID = 4L;
private static final Long CHANNEL_ID = 8L; private static final Long CHANNEL_ID = 8L;
@@ -213,35 +208,38 @@ public class RepostServiceBeanTest {
public void testProcessMessageAttachmentRepostCheckNoAttachment() { public void testProcessMessageAttachmentRepostCheckNoAttachment() {
when(message.getAttachments()).thenReturn(new ArrayList<>()); when(message.getAttachments()).thenReturn(new ArrayList<>());
testUnit.processMessageAttachmentRepostCheck(message); testUnit.processMessageAttachmentRepostCheck(message);
verify(message, times(0)).getTextChannel(); verify(message, times(0)).getChannelId();
} }
@Test @Test
public void testProcessMessageAttachmentRepostCheckOneAttachmentNotExistingPost() { public void testProcessMessageAttachmentRepostCheckOneAttachmentNotExistingPost() {
generalSetupForRepostTest(); generalSetupForRepostTest();
when(message.getMember()).thenReturn(member); when(message.getServerId()).thenReturn(SERVER_ID);
Message.Attachment attachment = Mockito.mock(Message.Attachment.class); when(author.getAuthorId()).thenReturn(USER_ID);
when(message.getAuthor()).thenReturn(author);
when(message.getMessageId()).thenReturn(MESSAGE_ID);
CachedAttachment attachment = Mockito.mock(CachedAttachment.class);
when(message.getAttachments()).thenReturn(Arrays.asList(attachment)); when(message.getAttachments()).thenReturn(Arrays.asList(attachment));
when(attachment.getProxyUrl()).thenReturn(URL); when(attachment.getProxyUrl()).thenReturn(URL);
setupSingleRepost(); setupSingleRepost();
testUnit.processMessageAttachmentRepostCheck(message); testUnit.processMessageAttachmentRepostCheck(message);
verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(message), eq(HASH), eq(0)); verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(MESSAGE_ID), eq(HASH), eq(0));
verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message); verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, CHANNEL_ID, MESSAGE_ID);
} }
@Test @Test
public void testProcessMessageAttachmentRepostCheckOneAttachmentIsRepost() { public void testProcessMessageAttachmentRepostCheckOneAttachmentIsRepost() {
generalSetupForRepostTest(); generalSetupForRepostTest();
setupForRepostCreation(); setupForRepostCreation();
Message.Attachment attachment = Mockito.mock(Message.Attachment.class); CachedAttachment attachment = Mockito.mock(CachedAttachment.class);
when(message.getAttachments()).thenReturn(Arrays.asList(attachment)); when(message.getAttachments()).thenReturn(Arrays.asList(attachment));
when(attachment.getProxyUrl()).thenReturn(URL); when(attachment.getProxyUrl()).thenReturn(URL);
setupSingleHash(postedImage); setupSingleHash(postedImage);
Long originalPostMessageId = MESSAGE_ID + 1; Long originalPostMessageId = MESSAGE_ID + 1;
when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION)); when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION));
when(messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message)).thenReturn(CompletableFuture.completedFuture(null)); when(messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, CHANNEL_ID, MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(null));
testUnit.processMessageAttachmentRepostCheck(message); testUnit.processMessageAttachmentRepostCheck(message);
verify(messageService, times(0)).addDefaultReactionToMessageAsync(anyString(), eq(message)); verify(messageService, times(0)).addDefaultReactionToMessageAsync(anyString(), eq(SERVER_ID), eq(CHANNEL_ID), eq(MESSAGE_ID));
verify(self, times(1)).persistRepost(originalPostMessageId, POSITION, SERVER_ID, USER_ID); verify(self, times(1)).persistRepost(originalPostMessageId, POSITION, SERVER_ID, USER_ID);
} }
@@ -249,9 +247,10 @@ public class RepostServiceBeanTest {
public void testProcessMessageAttachmentRepostCheckTwoAttachmentsOneIsRepost() { public void testProcessMessageAttachmentRepostCheckTwoAttachmentsOneIsRepost() {
generalSetupForRepostTest(); generalSetupForRepostTest();
setupForRepostCreation(); setupForRepostCreation();
when(message.getMember()).thenReturn(member); when(message.getServerId()).thenReturn(SERVER_ID);
Message.Attachment attachment = Mockito.mock(Message.Attachment.class); when(message.getAuthor().getAuthorId()).thenReturn(USER_ID);
Message.Attachment attachment2 = Mockito.mock(Message.Attachment.class); CachedAttachment attachment = Mockito.mock(CachedAttachment.class);
CachedAttachment attachment2 = Mockito.mock(CachedAttachment.class);
when(message.getAttachments()).thenReturn(Arrays.asList(attachment, attachment2)); when(message.getAttachments()).thenReturn(Arrays.asList(attachment, attachment2));
when(attachment.getProxyUrl()).thenReturn(URL); when(attachment.getProxyUrl()).thenReturn(URL);
setupSingleRepost(); setupSingleRepost();
@@ -262,30 +261,28 @@ public class RepostServiceBeanTest {
when(postedImageManagement.getPostWithHash(secondAttachmentHash, server)).thenReturn(Optional.of(postedImage)); when(postedImageManagement.getPostWithHash(secondAttachmentHash, server)).thenReturn(Optional.of(postedImage));
Long originalPostMessageId = MESSAGE_ID + 1; Long originalPostMessageId = MESSAGE_ID + 1;
when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION)); when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION));
when(messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message)).thenReturn(CompletableFuture.completedFuture(null)); when(messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, CHANNEL_ID, MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(null));
when(messageService.addDefaultReactionToMessageAsync(anyString(), eq(message))).thenReturn(CompletableFuture.completedFuture(null)); when(messageService.addDefaultReactionToMessageAsync(anyString(), eq(SERVER_ID), eq(CHANNEL_ID), eq(MESSAGE_ID))).thenReturn(CompletableFuture.completedFuture(null));
testUnit.processMessageAttachmentRepostCheck(message); testUnit.processMessageAttachmentRepostCheck(message);
verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(message), eq(HASH), eq(0)); verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(MESSAGE_ID), eq(HASH), eq(0));
verify(self, times(1)).persistRepost(originalPostMessageId, POSITION, SERVER_ID, USER_ID); verify(self, times(1)).persistRepost(originalPostMessageId, POSITION, SERVER_ID, USER_ID);
} }
private void setupForRepostCreation() { private void setupForRepostCreation() {
when(message.getIdLong()).thenReturn(MESSAGE_ID); when(message.getMessageId()).thenReturn(MESSAGE_ID);
when(message.getAuthor()).thenReturn(jdaUser); when(message.getServerId()).thenReturn(SERVER_ID);
when(jdaUser.getIdLong()).thenReturn(USER_ID); when(message.getAuthor()).thenReturn(author);
when(author.getAuthorId()).thenReturn(USER_ID);
when(message.getChannelId()).thenReturn(CHANNEL_ID);
} }
private void generalSetupForRepostTest() { private void generalSetupForRepostTest() {
when(message.getTextChannel()).thenReturn(textChannel); when(userInServerManagementService.loadUser(SERVER_ID, USER_ID)).thenReturn(userInAServer);
when(textChannel.getIdLong()).thenReturn(CHANNEL_ID);
when(message.getGuild()).thenReturn(guild);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server); when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
} }
private void setupSingleRepost() { private void setupSingleRepost() {
setupSingleHash(null); setupSingleHash(null);
when(userInServerManagementService.loadUser(member)).thenReturn(userInAServer);
when(userInAServer.getUserReference()).thenReturn(user); when(userInAServer.getUserReference()).thenReturn(user);
when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(channel); when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(channel);
} }
@@ -299,56 +296,62 @@ public class RepostServiceBeanTest {
@Test @Test
public void testProcessMessageEmbedsRepostCheckWithNotRepostedThumbnailNoAttachments() { public void testProcessMessageEmbedsRepostCheckWithNotRepostedThumbnailNoAttachments() {
generalSetupForRepostTest(); generalSetupForRepostTest();
MessageEmbed firstEmbed = Mockito.mock(MessageEmbed.class); CachedEmbed firstEmbed = Mockito.mock(CachedEmbed.class);
MessageEmbed.Thumbnail thumbnail = Mockito.mock(MessageEmbed.Thumbnail.class); CachedThumbnail thumbnail = Mockito.mock(CachedThumbnail.class);
when(thumbnail.getProxyUrl()).thenReturn(URL); when(thumbnail.getProxyUrl()).thenReturn(URL);
when(firstEmbed.getThumbnail()).thenReturn(thumbnail); when(firstEmbed.getCachedThumbnail()).thenReturn(thumbnail);
List<MessageEmbed> messageEmbeds = Arrays.asList(firstEmbed); List<CachedEmbed> messageEmbeds = Arrays.asList(firstEmbed);
when(message.getMember()).thenReturn(member); when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getAuthor()).thenReturn(author);
when(author.getAuthorId()).thenReturn(USER_ID);
when(message.getMessageId()).thenReturn(MESSAGE_ID);
when(message.getAttachments()).thenReturn(new ArrayList<>()); when(message.getAttachments()).thenReturn(new ArrayList<>());
setupSingleRepost(); setupSingleRepost();
testUnit.processMessageEmbedsRepostCheck(messageEmbeds, message); testUnit.processMessageEmbedsRepostCheck(messageEmbeds, message);
verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(message), eq(HASH), eq(EMBEDDED_LINK_POSITION_START_INDEX)); verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(MESSAGE_ID), eq(HASH), eq(EMBEDDED_LINK_POSITION_START_INDEX));
verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message); verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, CHANNEL_ID, MESSAGE_ID);
} }
@Test @Test
public void testProcessMessageEmbedsRepostCheckWithNotRepostedEmbedImageNoAttachments() { public void testProcessMessageEmbedsRepostCheckWithNotRepostedEmbedImageNoAttachments() {
generalSetupForRepostTest(); generalSetupForRepostTest();
MessageEmbed firstEmbed = Mockito.mock(MessageEmbed.class); CachedEmbed firstEmbed = Mockito.mock(CachedEmbed.class);
MessageEmbed.ImageInfo thumbnail = Mockito.mock(MessageEmbed.ImageInfo.class); CachedImageInfo image = Mockito.mock(CachedImageInfo.class);
when(thumbnail.getProxyUrl()).thenReturn(URL); when(image.getProxyUrl()).thenReturn(URL);
when(firstEmbed.getImage()).thenReturn(thumbnail); when(firstEmbed.getCachedImageInfo()).thenReturn(image);
List<MessageEmbed> messageEmbeds = Arrays.asList(firstEmbed); List<CachedEmbed> messageEmbeds = Arrays.asList(firstEmbed);
when(message.getMember()).thenReturn(member); when(message.getServerId()).thenReturn(SERVER_ID);
when(author.getAuthorId()).thenReturn(USER_ID);
when(message.getAuthor()).thenReturn(author);
when(message.getMessageId()).thenReturn(MESSAGE_ID);
when(message.getAttachments()).thenReturn(new ArrayList<>()); when(message.getAttachments()).thenReturn(new ArrayList<>());
setupSingleRepost(); setupSingleRepost();
testUnit.processMessageEmbedsRepostCheck(messageEmbeds, message); testUnit.processMessageEmbedsRepostCheck(messageEmbeds, message);
verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(message), eq(HASH), eq(EMBEDDED_LINK_POSITION_START_INDEX)); verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(MESSAGE_ID), eq(HASH), eq(EMBEDDED_LINK_POSITION_START_INDEX));
verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message); verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, CHANNEL_ID, MESSAGE_ID);
} }
@Test @Test
public void testProcessMessageEmbedsRepostCheckWithRepostedThumbnailNoAttachments() { public void testProcessMessageEmbedsRepostCheckWithRepostedThumbnailNoAttachments() {
generalSetupForRepostTest(); generalSetupForRepostTest();
setupForRepostCreation(); setupForRepostCreation();
MessageEmbed firstEmbed = Mockito.mock(MessageEmbed.class); CachedEmbed firstEmbed = Mockito.mock(CachedEmbed.class);
MessageEmbed.Thumbnail thumbnail = Mockito.mock(MessageEmbed.Thumbnail.class); CachedThumbnail thumbnail = Mockito.mock(CachedThumbnail.class);
when(thumbnail.getProxyUrl()).thenReturn(URL); when(thumbnail.getProxyUrl()).thenReturn(URL);
when(firstEmbed.getThumbnail()).thenReturn(thumbnail); when(firstEmbed.getCachedThumbnail()).thenReturn(thumbnail);
List<MessageEmbed> messageEmbeds = Arrays.asList(firstEmbed); List<CachedEmbed> messageEmbeds = Arrays.asList(firstEmbed);
when(message.getAttachments()).thenReturn(new ArrayList<>()); when(message.getAttachments()).thenReturn(new ArrayList<>());
setupSingleHash(postedImage); setupSingleHash(postedImage);
Long originalPostMessageId = MESSAGE_ID + 1; Long originalPostMessageId = MESSAGE_ID + 1;
when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION)); when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION));
when(messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message)).thenReturn(CompletableFuture.completedFuture(null)); when(messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, CHANNEL_ID, MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(null));
testUnit.processMessageEmbedsRepostCheck(messageEmbeds, message); testUnit.processMessageEmbedsRepostCheck(messageEmbeds, message);
verify(self, times(1)).persistRepost(originalPostMessageId, POSITION, SERVER_ID, USER_ID); verify(self, times(1)).persistRepost(originalPostMessageId, POSITION, SERVER_ID, USER_ID);
} }
@Test @Test
public void testIsRepostEmptyEmbedMessage() { public void testIsRepostEmptyEmbedMessage() {
MessageEmbed messageEmbed = Mockito.mock(MessageEmbed.class); CachedEmbed messageEmbed = Mockito.mock(CachedEmbed.class);
Optional<PostedImage> emptyOptional = testUnit.getRepostFor(message, messageEmbed, POSITION); Optional<PostedImage> emptyOptional = testUnit.getRepostFor(message, messageEmbed, POSITION);
Assert.assertFalse(emptyOptional.isPresent()); Assert.assertFalse(emptyOptional.isPresent());
} }
@@ -364,7 +367,7 @@ public class RepostServiceBeanTest {
} }
private void executeGetRepostForWithMessageId(Long originalPostMessageId, boolean shouldBePresent) { private void executeGetRepostForWithMessageId(Long originalPostMessageId, boolean shouldBePresent) {
MessageEmbed messageEmbed = setupSimpleRepostCheck(originalPostMessageId); CachedEmbed messageEmbed = setupSimpleRepostCheck(originalPostMessageId);
Optional<PostedImage> optional = testUnit.getRepostFor(message, messageEmbed, POSITION); Optional<PostedImage> optional = testUnit.getRepostFor(message, messageEmbed, POSITION);
Assert.assertEquals(shouldBePresent, optional.isPresent()); Assert.assertEquals(shouldBePresent, optional.isPresent());
if(shouldBePresent && optional.isPresent()) { if(shouldBePresent && optional.isPresent()) {
@@ -372,27 +375,27 @@ public class RepostServiceBeanTest {
} }
} }
private MessageEmbed setupSimpleRepostCheck(Long originalPostMessageId) { private CachedEmbed setupSimpleRepostCheck(Long originalPostMessageId) {
generalSetupForRepostTest(); generalSetupForRepostTest();
setupForRepostCreation(); setupForRepostCreation();
setupSingleHash(postedImage); setupSingleHash(postedImage);
when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION)); when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION));
MessageEmbed messageEmbed = Mockito.mock(MessageEmbed.class); CachedEmbed messageEmbed = Mockito.mock(CachedEmbed.class);
MessageEmbed.Thumbnail thumbnail = Mockito.mock(MessageEmbed.Thumbnail.class); CachedThumbnail thumbnail = Mockito.mock(CachedThumbnail.class);
when(thumbnail.getProxyUrl()).thenReturn(URL); when(thumbnail.getProxyUrl()).thenReturn(URL);
when(messageEmbed.getThumbnail()).thenReturn(thumbnail); when(messageEmbed.getCachedThumbnail()).thenReturn(thumbnail);
return messageEmbed; return messageEmbed;
} }
@Test @Test
public void testIsRepostWithRepost() { public void testIsRepostWithRepost() {
MessageEmbed messageEmbed = setupSimpleRepostCheck(MESSAGE_ID + 1); CachedEmbed messageEmbed = setupSimpleRepostCheck(MESSAGE_ID + 1);
Assert.assertTrue(testUnit.isRepost(message, messageEmbed, POSITION)); Assert.assertTrue(testUnit.isRepost(message, messageEmbed, POSITION));
} }
@Test @Test
public void testIsRepostWithSameMessage() { public void testIsRepostWithSameMessage() {
MessageEmbed messageEmbed = setupSimpleRepostCheck(MESSAGE_ID); CachedEmbed messageEmbed = setupSimpleRepostCheck(MESSAGE_ID);
Assert.assertFalse(testUnit.isRepost(message, messageEmbed, POSITION)); Assert.assertFalse(testUnit.isRepost(message, messageEmbed, POSITION));
} }
@@ -402,8 +405,11 @@ public class RepostServiceBeanTest {
setupSingleRepost(); setupSingleRepost();
setupSingleHash(postedImage); setupSingleHash(postedImage);
when(postedImage.getPostId()).thenReturn(new PostIdentifier(MESSAGE_ID + 1, POSITION)); when(postedImage.getPostId()).thenReturn(new PostIdentifier(MESSAGE_ID + 1, POSITION));
Message.Attachment attachment = Mockito.mock(Message.Attachment.class); CachedAttachment attachment = Mockito.mock(CachedAttachment.class);
when(attachment.getProxyUrl()).thenReturn(URL); when(attachment.getProxyUrl()).thenReturn(URL);
when(message.getServerId()).thenReturn(SERVER_ID);
when(author.getAuthorId()).thenReturn(USER_ID);
when(message.getAuthor()).thenReturn(author);
Assert.assertTrue(testUnit.isRepost(message, attachment, POSITION)); Assert.assertTrue(testUnit.isRepost(message, attachment, POSITION));
} }

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.exception.UserInServerNotFoundException; import dev.sheldan.abstracto.core.exception.UserInServerNotFoundException;
import dev.sheldan.abstracto.core.models.AServerAChannelMessage; import dev.sheldan.abstracto.core.models.AServerAChannelMessage;
import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.*; import dev.sheldan.abstracto.core.models.database.*;
import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.BotService;
@@ -14,7 +15,6 @@ import dev.sheldan.abstracto.core.service.management.PostTargetManagement;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import dev.sheldan.abstracto.core.test.MockUtils;
import dev.sheldan.abstracto.utility.config.posttargets.StarboardPostTarget; import dev.sheldan.abstracto.utility.config.posttargets.StarboardPostTarget;
import dev.sheldan.abstracto.utility.models.database.StarboardPost; import dev.sheldan.abstracto.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.models.database.StarboardPostReaction; import dev.sheldan.abstracto.utility.models.database.StarboardPostReaction;
@@ -102,10 +102,17 @@ public class StarboardServiceBeanTest {
@Mock @Mock
private MessageToSend messageToSend; private MessageToSend messageToSend;
@Mock
private AServer server;
private static final Long STARRED_USER_ID = 5L; private static final Long STARRED_USER_ID = 5L;
private static final Long STARRED_SERVER_USER_ID = 2L;
private static final Long SERVER_ID = 6L; private static final Long SERVER_ID = 6L;
private static final Long STARBOARD_CHANNEL_ID = 8L; private static final Long STARBOARD_CHANNEL_ID = 8L;
private static final Long FIRST_USER_IN_SERVER_ID = 3L;
private static final Long SECOND_USER_IN_SERVER_ID = 9L;
private static final Long CHANNEL_ID = 10L;
@Captor @Captor
private ArgumentCaptor<AUserInAServer> userInAServerArgumentCaptor; private ArgumentCaptor<AUserInAServer> userInAServerArgumentCaptor;
@@ -115,31 +122,33 @@ public class StarboardServiceBeanTest {
@Test @Test
public void testCreateStarboardPost() { public void testCreateStarboardPost() {
AServer server = MockUtils.getServer(); List<AUserInAServer> userExceptAuthor = new ArrayList<>();
List<AUserInAServer > userExceptAuthor = new ArrayList<>(); AUserInAServer firstUserExceptAuthor = Mockito.mock(AUserInAServer.class);
userExceptAuthor.add(MockUtils.getUserObject(2L, server)); userExceptAuthor.add(firstUserExceptAuthor);
userExceptAuthor.add(MockUtils.getUserObject(10L, server)); AUserInAServer secondUserExceptAuthor = Mockito.mock(AUserInAServer.class);
AUserInAServer userReacting = MockUtils.getUserObject(4L, server); userExceptAuthor.add(secondUserExceptAuthor);
AUserInAServer starredUser = MockUtils.getUserObject(5L, server); AUserInAServer userReacting = Mockito.mock(AUserInAServer.class);
Long channelId = 10L; AUserInAServer starredUser = Mockito.mock(AUserInAServer.class);
Long starredUserId = starredUser.getUserReference().getId(); when(starredUser.getUserInServerId()).thenReturn(STARRED_SERVER_USER_ID);
CachedMessage message = CachedMessage CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
.builder() when(cachedAuthor.getAuthorId()).thenReturn(STARRED_USER_ID);
.authorId(starredUserId) CachedMessage message = Mockito.mock(CachedMessage.class);
.serverId(server.getId()) when(message.getAuthor()).thenReturn(cachedAuthor);
.channelId(channelId) when(message.getServerId()).thenReturn(SERVER_ID);
.build(); when(message.getChannelId()).thenReturn(CHANNEL_ID);
Member authorMember = Mockito.mock(Member.class); Member authorMember = Mockito.mock(Member.class);
when(botService.getMemberInServerAsync(message.getServerId(), message.getAuthorId())).thenReturn(CompletableFuture.completedFuture(authorMember)); when(botService.getMemberInServerAsync(SERVER_ID, STARRED_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
when(botService.getTextChannelFromServerOptional(server.getId(), channelId)).thenReturn(Optional.of(mockedTextChannel)); when(botService.getTextChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.of(mockedTextChannel));
when(botService.getGuildByIdOptional(server.getId())).thenReturn(Optional.of(guild)); when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild));
ADefaultConfig config = ADefaultConfig.builder().longValue(3L).build(); ADefaultConfig config = Mockito.mock(ADefaultConfig.class);
when(config.getLongValue()).thenReturn(3L);
when(defaultConfigManagementService.getDefaultConfig(StarboardServiceBean.STAR_LEVELS_CONFIG_KEY)).thenReturn(config); when(defaultConfigManagementService.getDefaultConfig(StarboardServiceBean.STAR_LEVELS_CONFIG_KEY)).thenReturn(config);
when(configService.getLongValue("starLvl3", server.getId())).thenReturn(3L); when(configService.getLongValue("starLvl3", SERVER_ID)).thenReturn(3L);
when(configService.getLongValue("starLvl2", server.getId())).thenReturn(2L); when(configService.getLongValue("starLvl2", SERVER_ID)).thenReturn(2L);
when(emoteService.getUsableEmoteOrDefault(server.getId(), "star2")).thenReturn("b"); when(emoteService.getUsableEmoteOrDefault(SERVER_ID, "star2")).thenReturn("b");
when(self.sendStarboardPostAndStore(eq(message), eq(starredUserId), anyList(), any())).thenReturn(CompletableFuture.completedFuture(null)); when(self.sendStarboardPostAndStore(eq(message), eq(STARRED_SERVER_USER_ID), anyList(), any())).thenReturn(CompletableFuture.completedFuture(null));
testUnit.createStarboardPost(message, userExceptAuthor, userReacting, starredUser).join(); CompletableFuture<Void> createPostFuture = testUnit.createStarboardPost(message, userExceptAuthor, userReacting, starredUser);
Assert.assertTrue(createPostFuture.isDone());
} }
@Test @Test
@@ -159,116 +168,116 @@ public class StarboardServiceBeanTest {
} }
@Test @Test
public void testPersistPost() { public void testPersistPostWithTwoReactors() {
AServer server = MockUtils.getServer(); AUserInAServer userReacting = Mockito.mock(AUserInAServer.class);
AUserInAServer userReacting = MockUtils.getUserObject(4L, server); AUserInAServer starredUser = Mockito.mock(AUserInAServer.class);
AUserInAServer starredUser = MockUtils.getUserObject(5L, server); CachedMessage message = Mockito.mock(CachedMessage.class);
Long channelId = 10L; List<Long> userExceptAuthorIds = Arrays.asList(FIRST_USER_IN_SERVER_ID, SECOND_USER_IN_SERVER_ID);
CachedMessage message = CachedMessage
.builder()
.authorId(starredUser.getUserReference().getId())
.serverId(server.getId())
.channelId(channelId)
.build();
Long secondStarrerUserId = 2L;
List<Long> userExceptAuthorIds = Arrays.asList(secondStarrerUserId, userReacting.getUserReference().getId());
List<CompletableFuture<Message>> futures = Arrays.asList(CompletableFuture.completedFuture(sendPost)); List<CompletableFuture<Message>> futures = Arrays.asList(CompletableFuture.completedFuture(sendPost));
when(userInServerManagementService.loadUserConditional(starredUser.getUserInServerId())).thenReturn(Optional.of(starredUser)); when(userInServerManagementService.loadUserOptional(STARRED_SERVER_USER_ID)).thenReturn(Optional.of(starredUser));
when(userInServerManagementService.loadUserConditional(userReacting.getUserInServerId())).thenReturn(Optional.of(userReacting)); when(userInServerManagementService.loadUserOptional(FIRST_USER_IN_SERVER_ID)).thenReturn(Optional.of(userReacting));
AChannel channel = MockUtils.getTextChannel(server, channelId); when(userReacting.getUserInServerId()).thenReturn(FIRST_USER_IN_SERVER_ID);
when(channelManagementService.loadChannel(channelId)).thenReturn(channel); AChannel channel = Mockito.mock(AChannel.class);
StarboardPost post = StarboardPost.builder().build(); when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(channel);
StarboardPost post = Mockito.mock(StarboardPost.class);
when(starboardPostManagementService.createStarboardPost(eq(message), eq(starredUser), any(AServerAChannelMessage.class))).thenReturn(post); when(starboardPostManagementService.createStarboardPost(eq(message), eq(starredUser), any(AServerAChannelMessage.class))).thenReturn(post);
AUserInAServer secondStarrerUserObj = MockUtils.getUserObject(secondStarrerUserId, server); AUserInAServer secondStarrerUserObj = Mockito.mock(AUserInAServer.class);
when(userInServerManagementService.loadUserConditional(secondStarrerUserId)).thenReturn(Optional.of(secondStarrerUserObj)); when(userInServerManagementService.loadUserOptional(SECOND_USER_IN_SERVER_ID)).thenReturn(Optional.of(secondStarrerUserObj));
when(userInServerManagementService.loadUserConditional(userReacting.getUserInServerId())).thenReturn(Optional.of(userReacting)); when(secondStarrerUserObj.getUserInServerId()).thenReturn(SECOND_USER_IN_SERVER_ID);
testUnit.persistPost(message, userExceptAuthorIds, futures, channelId, starredUser.getUserInServerId()); testUnit.persistPost(message, userExceptAuthorIds, futures, CHANNEL_ID, STARRED_SERVER_USER_ID);
verify(starboardPostReactorManagementService, times(2)).addReactor(eq(post), userInAServerArgumentCaptor.capture()); verify(starboardPostReactorManagementService, times(2)).addReactor(eq(post), userInAServerArgumentCaptor.capture());
List<AUserInAServer> addedReactors = userInAServerArgumentCaptor.getAllValues(); List<AUserInAServer> addedReactors = userInAServerArgumentCaptor.getAllValues();
Assert.assertEquals(secondStarrerUserId, addedReactors.get(0).getUserInServerId()); Assert.assertEquals(FIRST_USER_IN_SERVER_ID, addedReactors.get(0).getUserInServerId());
Assert.assertEquals(userReacting.getUserInServerId(), addedReactors.get(1).getUserInServerId()); Assert.assertEquals(SECOND_USER_IN_SERVER_ID, addedReactors.get(1).getUserInServerId());
Assert.assertEquals(2, addedReactors.size()); Assert.assertEquals(2, addedReactors.size());
} }
@Test @Test
public void testUpdateStarboardPost() { public void testUpdateStarboardPost() {
AServer server = MockUtils.getServer(); Long newPostId = 37L;
Long postMessageId = 25L;
Long newPostId= 37L;
Long oldPostId = 36L; Long oldPostId = 36L;
AUserInAServer starredUser = MockUtils.getUserObject(5L, server);
Long channelId = 10L;
AChannel sourceChannel = Mockito.mock(AChannel.class); AChannel sourceChannel = Mockito.mock(AChannel.class);
when(sourceChannel.getServer()).thenReturn(server); when(sourceChannel.getServer()).thenReturn(server);
CachedMessage message = CachedMessage CachedMessage message = Mockito.mock(CachedMessage.class);
.builder() when(message.getChannelId()).thenReturn(CHANNEL_ID);
.authorId(starredUser.getUserReference().getId()) when(message.getServerId()).thenReturn(SERVER_ID);
.serverId(server.getId()) CachedAuthor author = Mockito.mock(CachedAuthor.class);
.channelId(channelId) when(author.getAuthorId()).thenReturn(STARRED_USER_ID);
.build(); when(message.getAuthor()).thenReturn(author);
Long starboardPostId = 47L; Long starboardPostId = 47L;
StarboardPost post = StarboardPost.builder().postMessageId(postMessageId).starboardMessageId(oldPostId).sourceChanel(sourceChannel).id(starboardPostId).build(); StarboardPost post = Mockito.mock(StarboardPost.class);
MessageToSend postMessage = MessageToSend.builder().build(); when(post.getStarboardMessageId()).thenReturn(oldPostId);
when(post.getSourceChanel()).thenReturn(sourceChannel);
when(post.getId()).thenReturn(starboardPostId);
MessageToSend postMessage = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(eq(STARBOARD_POST_TEMPLATE), starboardPostModelArgumentCaptor.capture())).thenReturn(postMessage); when(templateService.renderEmbedTemplate(eq(STARBOARD_POST_TEMPLATE), starboardPostModelArgumentCaptor.capture())).thenReturn(postMessage);
when(postTargetService.editOrCreatedInPostTarget(oldPostId, postMessage, StarboardPostTarget.STARBOARD, server.getId())).thenReturn(Arrays.asList(CompletableFuture.completedFuture(sendPost))); when(postTargetService.editOrCreatedInPostTarget(oldPostId, postMessage, StarboardPostTarget.STARBOARD, SERVER_ID)).thenReturn(Arrays.asList(CompletableFuture.completedFuture(sendPost)));
when(sendPost.getIdLong()).thenReturn(newPostId); when(sendPost.getIdLong()).thenReturn(newPostId);
ADefaultConfig config = ADefaultConfig.builder().longValue(4L).build(); ADefaultConfig config = Mockito.mock(ADefaultConfig.class);
when(config.getLongValue()).thenReturn(4L);
when(defaultConfigManagementService.getDefaultConfig(StarboardServiceBean.STAR_LEVELS_CONFIG_KEY)).thenReturn(config); when(defaultConfigManagementService.getDefaultConfig(StarboardServiceBean.STAR_LEVELS_CONFIG_KEY)).thenReturn(config);
when(starboardPostManagementService.findByStarboardPostId(starboardPostId)).thenReturn(Optional.of(post)); when(starboardPostManagementService.findByStarboardPostId(starboardPostId)).thenReturn(Optional.of(post));
when(botService.getMemberInServerAsync(server.getId(), starredUser.getUserReference().getId())).thenReturn(CompletableFuture.completedFuture(starredMember)); when(botService.getMemberInServerAsync(SERVER_ID, STARRED_USER_ID)).thenReturn(CompletableFuture.completedFuture(starredMember));
List<AUserInAServer > userExceptAuthor = new ArrayList<>(); List<AUserInAServer > userExceptAuthor = new ArrayList<>();
testUnit.updateStarboardPost(post, message, userExceptAuthor); testUnit.updateStarboardPost(post, message, userExceptAuthor);
verify(postTargetService, times(1)).editOrCreatedInPostTarget(oldPostId, postMessage, StarboardPostTarget.STARBOARD, server.getId()); verify(postTargetService, times(1)).editOrCreatedInPostTarget(oldPostId, postMessage, StarboardPostTarget.STARBOARD, SERVER_ID);
verify(starboardPostManagementService, times(1)).setStarboardPostMessageId(post, newPostId); verify(starboardPostManagementService, times(1)).setStarboardPostMessageId(post, newPostId);
} }
@Test @Test
public void testDeleteStarboardMessagePost() { public void testDeleteStarboardMessagePost() {
AServer server = MockUtils.getServer();
AChannel channel = MockUtils.getTextChannel(server, 4L);
Long messageId = 4L; Long messageId = 4L;
StarboardPost post = StarboardPost StarboardPost post = Mockito.mock(StarboardPost.class);
.builder() when(post.getStarboardMessageId()).thenReturn(messageId);
.starboardChannel(channel) AChannel channel = Mockito.mock(AChannel.class);
.sourceChanel(channel) when(channel.getServer()).thenReturn(server);
.starboardMessageId(messageId) when(server.getId()).thenReturn(SERVER_ID);
.build(); when(channel.getId()).thenReturn(CHANNEL_ID);
when(post.getSourceChanel()).thenReturn(channel);
when(post.getStarboardChannel()).thenReturn(channel);
testUnit.deleteStarboardMessagePost(post); testUnit.deleteStarboardMessagePost(post);
verify(botService, times(1)).deleteMessage(server.getId(), channel.getId(), messageId); verify(botService, times(1)).deleteMessage(SERVER_ID, CHANNEL_ID, messageId);
} }
@Test(expected = UserInServerNotFoundException.class) @Test(expected = UserInServerNotFoundException.class)
public void testPersistingOfNotFoundStarredUser() { public void testPersistingOfNotFoundStarredUser() {
AServer server = MockUtils.getServer(); when(userInServerManagementService.loadUserOptional(SECOND_USER_IN_SERVER_ID)).thenReturn(Optional.empty());
AUserInAServer userReacting = MockUtils.getUserObject(4L, server); CachedMessage message = Mockito.mock(CachedMessage.class);
AUserInAServer starredUser = MockUtils.getUserObject(5L, server); List<Long> userExceptAuthorIds = Arrays.asList(FIRST_USER_IN_SERVER_ID);
when(userInServerManagementService.loadUserConditional(starredUser.getUserInServerId())).thenReturn(Optional.empty()); List<CompletableFuture<Message>> futures = Arrays.asList(CompletableFuture.completedFuture(sendPost));
executeLoadErrorTest(server, userReacting, starredUser, 10L); testUnit.persistPost(message, userExceptAuthorIds, futures, CHANNEL_ID, SECOND_USER_IN_SERVER_ID);
} }
@Test @Test
public void testRetrieveStarStats() { public void testRetrieveStarStats() {
AServer server = MockUtils.getServer();
Integer limit = 3; Integer limit = 3;
AChannel channel = MockUtils.getTextChannel(server, 4L); AChannel channel = Mockito.mock(AChannel.class);
when(channel.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
Long firstPostMessageId = 50L; Long firstPostMessageId = 50L;
Long secondPostMessageId = 51L; Long secondPostMessageId = 51L;
StarboardPostReaction reaction = StarboardPostReaction.builder().build(); StarboardPostReaction reaction = Mockito.mock(StarboardPostReaction.class);
StarboardPost post1 = StarboardPost.builder().starboardChannel(channel).postMessageId(firstPostMessageId).reactions(Arrays.asList(reaction)).build(); StarboardPost post1 = Mockito.mock(StarboardPost.class);
StarboardPost post2 = StarboardPost.builder().starboardChannel(channel).postMessageId(secondPostMessageId).reactions(new ArrayList<>()).build(); when(post1.getReactions()).thenReturn(Arrays.asList(reaction));
when(post1.getPostMessageId()).thenReturn(firstPostMessageId);
when(post1.getStarboardChannel()).thenReturn(channel);
StarboardPost post2 = Mockito.mock(StarboardPost.class);
when(post2.getPostMessageId()).thenReturn(secondPostMessageId);
when(post2.getReactions()).thenReturn(new ArrayList<>());
when(post2.getStarboardChannel()).thenReturn(channel);
List<StarboardPost> topPosts = Arrays.asList(post1, post2); List<StarboardPost> topPosts = Arrays.asList(post1, post2);
when(starboardPostManagementService.retrieveTopPosts(server.getId(), limit)).thenReturn(topPosts); when(starboardPostManagementService.retrieveTopPosts(SERVER_ID, limit)).thenReturn(topPosts);
CompletableFuture<StarStatsUser> statsUser = CompletableFuture.completedFuture(Mockito.mock(StarStatsUser.class)); CompletableFuture<StarStatsUser> statsUser = CompletableFuture.completedFuture(Mockito.mock(StarStatsUser.class));
CompletableFuture<StarStatsUser> statsUser2 = CompletableFuture.completedFuture(Mockito.mock(StarStatsUser.class)); CompletableFuture<StarStatsUser> statsUser2 = CompletableFuture.completedFuture(Mockito.mock(StarStatsUser.class));
List<CompletableFuture<StarStatsUser>> topGiver = Arrays.asList(statsUser, statsUser2); List<CompletableFuture<StarStatsUser>> topGiver = Arrays.asList(statsUser, statsUser2);
when(starboardPostReactorManagementService.retrieveTopStarGiver(server.getId(), limit)).thenReturn(topGiver); when(starboardPostReactorManagementService.retrieveTopStarGiver(SERVER_ID, limit)).thenReturn(topGiver);
when(starboardPostReactorManagementService.retrieveTopStarReceiver(server.getId(), limit)).thenReturn(topGiver); when(starboardPostReactorManagementService.retrieveTopStarReceiver(SERVER_ID, limit)).thenReturn(topGiver);
when(starboardPostManagementService.getPostCount(server.getId())).thenReturn(50); when(starboardPostManagementService.getPostCount(SERVER_ID)).thenReturn(50);
when(starboardPostReactorManagementService.getStarCount(server.getId())).thenReturn(500); when(starboardPostReactorManagementService.getStarCount(SERVER_ID)).thenReturn(500);
when(emoteService.getUsableEmoteOrDefault(server.getId(), "starboardBadge1")).thenReturn("1"); when(emoteService.getUsableEmoteOrDefault(SERVER_ID, "starboardBadge1")).thenReturn("1");
when(emoteService.getUsableEmoteOrDefault(server.getId(), "starboardBadge2")).thenReturn("2"); when(emoteService.getUsableEmoteOrDefault(SERVER_ID, "starboardBadge2")).thenReturn("2");
when(emoteService.getUsableEmoteOrDefault(server.getId(), "starboardBadge3")).thenReturn("3"); when(emoteService.getUsableEmoteOrDefault(SERVER_ID, "starboardBadge3")).thenReturn("3");
CompletableFuture<StarStatsModel> modelFuture = testUnit.retrieveStarStats(server.getId()); CompletableFuture<StarStatsModel> modelFuture = testUnit.retrieveStarStats(SERVER_ID);
StarStatsModel model = modelFuture.join(); StarStatsModel model = modelFuture.join();
List<String> badgeEmotes = model.getBadgeEmotes(); List<String> badgeEmotes = model.getBadgeEmotes();
Assert.assertEquals(limit.intValue(), badgeEmotes.size()); Assert.assertEquals(limit.intValue(), badgeEmotes.size());
@@ -278,28 +287,16 @@ public class StarboardServiceBeanTest {
Assert.assertEquals(500, model.getTotalStars().intValue()); Assert.assertEquals(500, model.getTotalStars().intValue());
Assert.assertEquals(50, model.getStarredMessages().intValue()); Assert.assertEquals(50, model.getStarredMessages().intValue());
StarStatsPost topPost = model.getTopPosts().get(0); StarStatsPost topPost = model.getTopPosts().get(0);
Assert.assertEquals(server.getId(), topPost.getServerId()); Assert.assertEquals(SERVER_ID, topPost.getServerId());
Assert.assertEquals(channel.getId(), topPost.getChannelId()); Assert.assertEquals(channel.getId(), topPost.getChannelId());
Assert.assertEquals(firstPostMessageId, topPost.getMessageId()); Assert.assertEquals(firstPostMessageId, topPost.getMessageId());
Assert.assertEquals(1, topPost.getStarCount().intValue()); Assert.assertEquals(1, topPost.getStarCount().intValue());
StarStatsPost secondTopPost = model.getTopPosts().get(1); StarStatsPost secondTopPost = model.getTopPosts().get(1);
Assert.assertEquals(server.getId(), secondTopPost.getServerId()); Assert.assertEquals(SERVER_ID, secondTopPost.getServerId());
Assert.assertEquals(channel.getId(), secondTopPost.getChannelId()); Assert.assertEquals(channel.getId(), secondTopPost.getChannelId());
Assert.assertEquals(secondPostMessageId, secondTopPost.getMessageId()); Assert.assertEquals(secondPostMessageId, secondTopPost.getMessageId());
Assert.assertEquals(0, secondTopPost.getStarCount().intValue()); Assert.assertEquals(0, secondTopPost.getStarCount().intValue());
} }
private void executeLoadErrorTest(AServer server, AUserInAServer userReacting, AUserInAServer starredUser, Long channelId) {
CachedMessage message = CachedMessage
.builder()
.authorId(starredUser.getUserReference().getId())
.serverId(server.getId())
.channelId(channelId)
.build();
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());
}
} }

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.utility.service.management; package dev.sheldan.abstracto.utility.service.management;
import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
@@ -11,9 +12,7 @@ import dev.sheldan.abstracto.core.test.MockUtils;
import dev.sheldan.abstracto.utility.exception.CrossServerEmbedException; import dev.sheldan.abstracto.utility.exception.CrossServerEmbedException;
import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage; import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage;
import dev.sheldan.abstracto.utility.repository.EmbeddedMessageRepository; import dev.sheldan.abstracto.utility.repository.EmbeddedMessageRepository;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -45,43 +44,53 @@ public class MessageEmbedPostManagementServiceBeanTest {
@Captor @Captor
private ArgumentCaptor<EmbeddedMessage> messageArgumentCaptor; private ArgumentCaptor<EmbeddedMessage> messageArgumentCaptor;
private static final Long SERVER_ID = 1L;
private static final Long EMBEDDING_CHANNEL_ID = 2L;
private static final Long EMBEDDED_MESSAGE_ID = 5L;
private static final Long EMBEDDING_MESSAGE_ID = 7L;
private static final Long EMBEDDED_USER_ID = 8L;
private static final Long EMBEDDING_USER_ID = 9L;
@Test @Test
public void testCreateCorrectEmbed(){ public void testCreateCorrectEmbed() {
AServer server = MockUtils.getServer(); AUserInAServer embeddingUser = Mockito.mock(AUserInAServer.class);
AUserInAServer embeddingUser = MockUtils.getUserObject(5L, server); AUserInAServer embeddedUser = Mockito.mock(AUserInAServer.class);
AUserInAServer embeddedUser = MockUtils.getUserObject(7L, server); AChannel channel = Mockito.mock(AChannel.class);
AChannel channel = MockUtils.getTextChannel(server, 8L); AServer server = Mockito.mock(AServer.class);
when(serverManagementService.loadOrCreate(server.getId())).thenReturn(server); when(server.getId()).thenReturn(SERVER_ID);
when(channelManagementService.loadChannel(channel.getId())).thenReturn(channel); when(serverManagementService.loadOrCreate(SERVER_ID)).thenReturn(server);
Long embeddedMessageId = 5L; when(channelManagementService.loadChannel(EMBEDDING_CHANNEL_ID)).thenReturn(channel);
Long embeddingMessageId = 7L; CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
CachedMessage cachedMessage = CachedMessage when(cachedMessage.getMessageId()).thenReturn(EMBEDDED_MESSAGE_ID);
.builder() when(cachedMessage.getServerId()).thenReturn(SERVER_ID);
.messageId(embeddedMessageId) when(cachedMessage.getChannelId()).thenReturn(EMBEDDING_CHANNEL_ID);
.channelId(channel.getId()) CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
.serverId(server.getId()) when(cachedAuthor.getAuthorId()).thenReturn(EMBEDDED_USER_ID);
.authorId(embeddedUser.getUserReference().getId()) when(cachedMessage.getAuthor()).thenReturn(cachedAuthor);
.build(); when(cachedMessage.getServerId()).thenReturn(SERVER_ID);
Message message = Mockito.mock(Message.class); Message embeddingMessage = Mockito.mock(Message.class);
MessageChannel embeddingChannel = Mockito.mock(MessageChannel.class);
when(embeddingChannel.getIdLong()).thenReturn(EMBEDDING_CHANNEL_ID);
when(embeddingMessage.getChannel()).thenReturn(embeddingChannel);
User embeddingJdaUser = Mockito.mock(User.class);
when(embeddingJdaUser.getIdLong()).thenReturn(EMBEDDING_USER_ID);
when(embeddingMessage.getAuthor()).thenReturn(embeddingJdaUser);
Guild guild = Mockito.mock(Guild.class); Guild guild = Mockito.mock(Guild.class);
MessageChannel embeddedChannel = Mockito.mock(MessageChannel.class); when(embeddingMessage.getGuild()).thenReturn(guild);
when(message.getChannel()).thenReturn(embeddedChannel); when(guild.getIdLong()).thenReturn(SERVER_ID);
when(message.getGuild()).thenReturn(guild); when(embeddingMessage.getIdLong()).thenReturn(EMBEDDING_MESSAGE_ID);
when(guild.getIdLong()).thenReturn(server.getId()); when(userInServerManagementService.loadUser(SERVER_ID, EMBEDDED_USER_ID)).thenReturn(embeddedUser);
when(message.getIdLong()).thenReturn(embeddingMessageId); testUnit.createMessageEmbed(cachedMessage, embeddingMessage, embeddingUser);
when(embeddedChannel.getIdLong()).thenReturn(channel.getId());
when(userInServerManagementService.loadUser(server.getId(), embeddedUser.getUserReference().getId())).thenReturn(embeddedUser);
testUnit.createMessageEmbed(cachedMessage, message, embeddingUser);
verify(embeddedMessageRepository, times(1)).save(messageArgumentCaptor.capture()); verify(embeddedMessageRepository, times(1)).save(messageArgumentCaptor.capture());
EmbeddedMessage savedMessage = messageArgumentCaptor.getValue(); EmbeddedMessage savedMessage = messageArgumentCaptor.getValue();
Assert.assertEquals(embeddedMessageId, savedMessage.getEmbeddedMessageId()); Assert.assertEquals(EMBEDDED_MESSAGE_ID, savedMessage.getEmbeddedMessageId());
Assert.assertEquals(channel, savedMessage.getEmbeddedChannel()); Assert.assertEquals(channel, savedMessage.getEmbeddedChannel());
Assert.assertEquals(channel, savedMessage.getEmbeddingChannel()); Assert.assertEquals(channel, savedMessage.getEmbeddingChannel());
Assert.assertEquals(embeddedUser, savedMessage.getEmbeddedUser()); Assert.assertEquals(embeddedUser, savedMessage.getEmbeddedUser());
Assert.assertEquals(embeddingUser, savedMessage.getEmbeddingUser()); Assert.assertEquals(embeddingUser, savedMessage.getEmbeddingUser());
Assert.assertEquals(server, savedMessage.getEmbeddedServer()); Assert.assertEquals(server, savedMessage.getEmbeddedServer());
Assert.assertEquals(server, savedMessage.getEmbeddingServer()); Assert.assertEquals(server, savedMessage.getEmbeddingServer());
Assert.assertEquals(embeddingMessageId, savedMessage.getEmbeddingMessageId()); Assert.assertEquals(EMBEDDING_MESSAGE_ID, savedMessage.getEmbeddingMessageId());
} }
@Test(expected = CrossServerEmbedException.class) @Test(expected = CrossServerEmbedException.class)

View File

@@ -9,7 +9,6 @@ import dev.sheldan.abstracto.utility.models.database.PostedImage;
import dev.sheldan.abstracto.utility.models.database.embed.PostIdentifier; import dev.sheldan.abstracto.utility.models.database.embed.PostIdentifier;
import dev.sheldan.abstracto.utility.repository.PostedImageRepository; import dev.sheldan.abstracto.utility.repository.PostedImageRepository;
import dev.sheldan.abstracto.utility.service.RepostServiceBean; import dev.sheldan.abstracto.utility.service.RepostServiceBean;
import net.dv8tion.jda.api.entities.Message;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -53,12 +52,10 @@ public class PostedImageManagementBeanTest {
public void testCreatePost() { public void testCreatePost() {
AServerAChannelAUser serverAChannelAUser = Mockito.mock(AServerAChannelAUser.class); AServerAChannelAUser serverAChannelAUser = Mockito.mock(AServerAChannelAUser.class);
AChannel channel = Mockito.mock(AChannel.class); AChannel channel = Mockito.mock(AChannel.class);
Message message = Mockito.mock(Message.class);
when(message.getIdLong()).thenReturn(MESSAGE_ID);
when(serverAChannelAUser.getGuild()).thenReturn(server); when(serverAChannelAUser.getGuild()).thenReturn(server);
when(serverAChannelAUser.getChannel()).thenReturn(channel); when(serverAChannelAUser.getChannel()).thenReturn(channel);
when(serverAChannelAUser.getAUserInAServer()).thenReturn(aUserInAServer); when(serverAChannelAUser.getAUserInAServer()).thenReturn(aUserInAServer);
PostedImage createdPost = testUnit.createPost(serverAChannelAUser, message, HASH, INDEX); PostedImage createdPost = testUnit.createPost(serverAChannelAUser, MESSAGE_ID, HASH, INDEX);
Assert.assertEquals(HASH, createdPost.getImageHash()); Assert.assertEquals(HASH, createdPost.getImageHash());
Assert.assertEquals(INDEX, createdPost.getPostId().getPosition()); Assert.assertEquals(INDEX, createdPost.getPostId().getPosition());
Assert.assertEquals(MESSAGE_ID, createdPost.getPostId().getMessageId()); Assert.assertEquals(MESSAGE_ID, createdPost.getPostId().getMessageId());

View File

@@ -1,5 +1,8 @@
package dev.sheldan.abstracto.utility.service; package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.models.cache.CachedAttachment;
import dev.sheldan.abstracto.core.models.cache.CachedEmbed;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.utility.models.RepostLeaderboardEntryModel; import dev.sheldan.abstracto.utility.models.RepostLeaderboardEntryModel;
import dev.sheldan.abstracto.utility.models.database.PostedImage; import dev.sheldan.abstracto.utility.models.database.PostedImage;
@@ -10,12 +13,14 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public interface RepostService { public interface RepostService {
boolean isRepost(Message message, MessageEmbed messageEmbed, Integer embedIndex); boolean isRepost(CachedMessage message, CachedEmbed messageEmbed, Integer embedIndex);
Optional<PostedImage> getRepostFor(CachedMessage message, CachedEmbed messageEmbed, Integer embedIndex);
Optional<PostedImage> getRepostFor(Message message, MessageEmbed messageEmbed, Integer embedIndex); Optional<PostedImage> getRepostFor(Message message, MessageEmbed messageEmbed, Integer embedIndex);
boolean isRepost(Message message, Message.Attachment attachment, Integer index); boolean isRepost(CachedMessage message, CachedAttachment attachment, Integer index);
Optional<PostedImage> getRepostFor(Message message, Message.Attachment attachment, Integer index); Optional<PostedImage> getRepostFor(CachedMessage message, CachedAttachment attachment, Integer index);
String calculateHashForPost(String url, Long serverId); String calculateHashForPost(String url, Long serverId);
void processMessageAttachmentRepostCheck(Message message); void processMessageAttachmentRepostCheck(CachedMessage message);
void processMessageEmbedsRepostCheck(List<CachedEmbed> embeds, CachedMessage message);
void processMessageEmbedsRepostCheck(List<MessageEmbed> embeds, Message message); void processMessageEmbedsRepostCheck(List<MessageEmbed> embeds, Message message);
CompletableFuture<List<RepostLeaderboardEntryModel>> retrieveRepostLeaderboard(Guild guild, Integer page); CompletableFuture<List<RepostLeaderboardEntryModel>> retrieveRepostLeaderboard(Guild guild, Integer page);
void purgeReposts(AUserInAServer userInAServer); void purgeReposts(AUserInAServer userInAServer);

View File

@@ -4,13 +4,12 @@ import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.utility.models.database.PostedImage; import dev.sheldan.abstracto.utility.models.database.PostedImage;
import net.dv8tion.jda.api.entities.Message;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface PostedImageManagement { public interface PostedImageManagement {
PostedImage createPost(AServerAChannelAUser creation, Message source, String hash, Integer index); PostedImage createPost(AServerAChannelAUser creation, Long messageId, String hash, Integer index);
boolean postWitHashExists(String hash, AServer server); boolean postWitHashExists(String hash, AServer server);
Optional<PostedImage> getPostWithHash(String hash, AServer server); Optional<PostedImage> getPostWithHash(String hash, AServer server);
boolean messageHasBeenCovered(Long messageId); boolean messageHasBeenCovered(Long messageId);

View File

@@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.models.database.ACommand; import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService; import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService; import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.listener.ServerConfigListener; import dev.sheldan.abstracto.core.listener.sync.entity.ServerConfigListener;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -162,10 +162,15 @@ public class CommandServiceBean implements CommandService {
} }
} }
@Override
public UnParsedCommandParameter getUnParsedCommandParameter(String messageContent) {
return new UnParsedCommandParameter(messageContent);
}
@Override @Override
public CompletableFuture<Parameters> getParametersForCommand(String commandName, Message messageContainingContent) { public CompletableFuture<Parameters> getParametersForCommand(String commandName, Message messageContainingContent) {
String contentStripped = messageContainingContent.getContentRaw(); String contentStripped = messageContainingContent.getContentRaw();
UnParsedCommandParameter unParsedParameter = new UnParsedCommandParameter(contentStripped); UnParsedCommandParameter unParsedParameter = getUnParsedCommandParameter(contentStripped);
Command command = commandRegistry.findCommandByParameters(commandName, unParsedParameter); Command command = commandRegistry.findCommandByParameters(commandName, unParsedParameter);
return commandReceivedHandler.getParsedParameters(unParsedParameter, command, messageContainingContent); return commandReceivedHandler.getParsedParameters(unParsedParameter, command, messageContainingContent);
} }

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.core.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:listenerConfig.properties")
public class ListenerConfig {
}

View File

@@ -0,0 +1,117 @@
package dev.sheldan.abstracto.core.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class ListenerExecutorConfig {
@Value("${abstracto.listener.default.maxPoolSize}")
private Integer defaultMaxPoolSize;
@Value("${abstracto.listener.default.corePoolSize}")
private Integer defaultCorePoolSize;
@Value("${abstracto.listener.default.keepAliveSeconds}")
private Integer defaultKeepAliveSeconds;
@Autowired
private Environment environment;
private static final String LISTENER_PREFIX = "abstracto.listener.";
private static final String LISTENER_MAX_POOL_SIZE = "maxPoolSize";
private static final String LISTENER_CORE_POOL_SIZE = "corePoolSize";
private static final String LISTENER_KEEP_ALIVE_SECONDS = "keepAliveSeconds";
@Bean(name = "joinListenerExecutor")
public TaskExecutor joinListenerExecutor() {
return setupExecutorFor("joinListener");
}
@Bean(name = "leaveListenerExecutor")
public TaskExecutor leaveListenerExecutor() {
return setupExecutorFor("leaveListener");
}
@Bean(name = "messageReceivedExecutor")
public TaskExecutor messageReceivedExecutor() {
return setupExecutorFor("messageReceivedListener");
}
@Bean(name = "messageDeletedExecutor")
public TaskExecutor messageDeletedExecutor() {
return setupExecutorFor("messageReceivedListener");
}
@Bean(name = "messageEmbeddedExecutor")
public TaskExecutor messageEmbeddedExecutor() {
return setupExecutorFor("messageEmbeddedListener");
}
@Bean(name = "messageUpdatedExecutor")
public TaskExecutor messageUpdatedExecutor() {
return setupExecutorFor("messageUpdatedListener");
}
@Bean(name = "privateMessageReceivedExecutor")
public TaskExecutor privateMessageReceivedExecutor() {
return setupExecutorFor("privateMessageReceivedListener");
}
@Bean(name = "emoteCreatedExecutor")
public TaskExecutor emoteCreatedExecutor() {
return setupExecutorFor("emoteCreatedListener");
}
@Bean(name = "emoteDeletedExecutor")
public TaskExecutor emoteDeletedExecutor() {
return setupExecutorFor("emoteDeletedListener");
}
@Bean(name = "emoteUpdatedExecutor")
public TaskExecutor emoteUpdatedExecutor() {
return setupExecutorFor("emoteUpdatedListener");
}
@Bean(name = "reactionAddedExecutor")
public TaskExecutor reactionAddedExecutor() {
return setupExecutorFor("reactionAddedListener");
}
@Bean(name = "reactionRemovedExecutor")
public TaskExecutor reactionRemovedExecutor() {
return setupExecutorFor("reactionRemovedListener");
}
@Bean(name = "reactionClearedExecutor")
public TaskExecutor reactionClearedExecutor() {
return setupExecutorFor("reactionClearedListener");
}
public ThreadPoolTaskExecutor setupExecutorFor(String listenerName) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
Integer maxPoolSize = getPropertyValueInteger(listenerName, LISTENER_MAX_POOL_SIZE, defaultMaxPoolSize.toString());
Integer corePoolSize = getPropertyValueInteger(listenerName, LISTENER_CORE_POOL_SIZE, defaultCorePoolSize.toString());
Integer keepAliveSeconds = getPropertyValueInteger(listenerName, LISTENER_KEEP_ALIVE_SECONDS, defaultKeepAliveSeconds.toString());
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setThreadNamePrefix(listenerName + "-task-executor-thread");
executor.initialize();
return executor;
}
public String getPropertyValue(String listenerName, String key, String defaultValue) {
return environment.getProperty(LISTENER_PREFIX + listenerName + "." + key, defaultValue);
}
public Integer getPropertyValueInteger(String listenerName, String key, String defaultValue) {
return Integer.parseInt(getPropertyValue(listenerName, key, defaultValue));
}
}

View File

@@ -1,114 +0,0 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.events.emote.EmoteAddedEvent;
import net.dv8tion.jda.api.events.emote.EmoteRemovedEvent;
import net.dv8tion.jda.api.events.emote.update.EmoteUpdateNameEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.List;
@Service
@Slf4j
public class EmoteListener extends ListenerAdapter {
@Autowired
private List<EmoteCreatedListener> createdListeners;
@Autowired
private List<EmoteDeletedListener> deletedListeners;
@Autowired
private List<EmoteUpdatedListener> updatedListeners;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureModeService featureModeService;
@Autowired
@Lazy
private EmoteListener self;
@Override
@Transactional
public void onEmoteAdded(@NotNull EmoteAddedEvent event) {
createdListeners.forEach(listener -> {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(listener.getFeature());
if (!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
return;
}
if(!featureModeService.necessaryFeatureModesMet(listener, event.getGuild().getIdLong())) {
return;
}
self.executeCreatedListener(listener, event.getEmote());
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeCreatedListener(EmoteCreatedListener listener, Emote createDdEmote) {
listener.emoteCreated(createDdEmote);
}
@Override
public void onEmoteRemoved(@NotNull EmoteRemovedEvent event) {
deletedListeners.forEach(listener -> {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(listener.getFeature());
if (!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
return;
}
if(!featureModeService.necessaryFeatureModesMet(listener, event.getGuild().getIdLong())) {
return;
}
self.executeDeletedListener(listener, event.getEmote());
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeDeletedListener(EmoteDeletedListener listener, Emote createDdEmote) {
listener.emoteDeleted(createDdEmote);
}
@Override
public void onEmoteUpdateName(@NotNull EmoteUpdateNameEvent event) {
updatedListeners.forEach(emoteUpdatedListener -> {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(emoteUpdatedListener.getFeature());
if (!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
return;
}
if(!featureModeService.necessaryFeatureModesMet(emoteUpdatedListener, event.getGuild().getIdLong())) {
return;
}
self.executeUpdatedListener(emoteUpdatedListener, event.getEmote(), event.getOldName(), event.getNewName());
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeUpdatedListener(EmoteUpdatedListener listener, Emote updatedEmote, String oldName, String newName) {
listener.emoteUpdated(updatedEmote, oldName, newName);
}
@PostConstruct
public void postConstruct() {
createdListeners.sort(Comparator.comparing(Prioritized::getPriority).reversed());
deletedListeners.sort(Comparator.comparing(Prioritized::getPriority).reversed());
updatedListeners.sort(Comparator.comparing(Prioritized::getPriority).reversed());
}
}

View File

@@ -1,99 +0,0 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.command.service.ExceptionService;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.MessageCache;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.List;
@Component
@Slf4j
public class MessageReceivedListenerBean extends ListenerAdapter {
@Autowired
private MessageCache messageCache;
@Autowired
private List<MessageReceivedListener> listenerList;
@Autowired
private List<PrivateMessageReceivedListener> privateMessageReceivedListeners;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private BotService botService;
@Autowired
private ExceptionService exceptionService;
@Autowired
private MessageReceivedListenerBean self;
@Override
public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) {
messageCache.putMessageInCache(event.getMessage());
listenerList.forEach(messageReceivedListener -> {
try {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(messageReceivedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
return;
}
self.executeIndividualGuildMessageReceivedListener(event, messageReceivedListener);
} catch (Exception e) {
log.error("Listener {} had exception when executing.", messageReceivedListener, e);
exceptionService.reportExceptionToGuildMessageReceivedContext(e, event);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualGuildMessageReceivedListener(@Nonnull GuildMessageReceivedEvent event, MessageReceivedListener messageReceivedListener) {
messageReceivedListener.execute(event.getMessage());
}
@Override
public void onPrivateMessageReceived(@Nonnull PrivateMessageReceivedEvent event) {
if(event.getAuthor().getId().equals(botService.getInstance().getSelfUser().getId())) {
return;
}
privateMessageReceivedListeners.forEach(messageReceivedListener -> {
try {
self.executeIndividualPrivateMessageReceivedListener(event, messageReceivedListener);
} catch (Exception e) {
log.error("Listener {} had exception when executing.", messageReceivedListener, e);
exceptionService.reportExceptionToPrivateMessageReceivedContext(e, event);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualPrivateMessageReceivedListener(@Nonnull PrivateMessageReceivedEvent event, PrivateMessageReceivedListener messageReceivedListener) {
log.trace("Executing private message listener {} for member {}.", messageReceivedListener.getClass().getName(), event.getAuthor().getId());
messageReceivedListener.execute(event.getMessage());
}
@PostConstruct
public void postConstruct() {
listenerList.sort(Comparator.comparing(Prioritized::getPriority).reversed());
privateMessageReceivedListeners.sort(Comparator.comparing(Prioritized::getPriority).reversed());
}
}

View File

@@ -1,210 +0,0 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReaction;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveAllEvent;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class ReactionUpdatedListener extends ListenerAdapter {
@Autowired
private MessageCache messageCache;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private List<ReactedAddedListener> addedListenerList;
@Autowired
private List<ReactionClearedListener> clearedListenerList;
@Autowired
private List<ReactedRemovedListener> reactionRemovedListeners;
@Autowired
private ReactionUpdatedListener self;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private BotService botService;
@Autowired
private EmoteService emoteService;
@Override
@Transactional
public void onGuildMessageReactionAdd(@Nonnull GuildMessageReactionAddEvent event) {
if(event.getUserIdLong() == botService.getInstance().getSelfUser().getIdLong()) {
return;
}
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
asyncMessageFromCache.thenAccept(cachedMessage ->
messageCache.getCachedReactionFromReaction(event.getReaction()).thenAccept(reaction -> {
self.callAddedListeners(event, cachedMessage, reaction);
messageCache.putMessageInCache(cachedMessage);
}).exceptionally(throwable -> {
log.error("Failed to handle add reaction to message {} ", event.getMessageIdLong(), throwable);
return null;
})
).exceptionally(throwable -> {
log.error("Message retrieval {} from cache failed. ", event.getMessageIdLong(), throwable);
return null;
});
}
private void addReactionIfNotThere(CachedMessage message, CachedReaction reaction, AUserInAServer userReacting) {
Optional<CachedReaction> existingReaction = message.getReactions().stream().filter(reaction1 ->
emoteService.compareAEmote(reaction1.getEmote(), reaction.getEmote())
).findAny();
if(!existingReaction.isPresent()) {
message.getReactions().add(reaction);
} else {
CachedReaction cachedReaction = existingReaction.get();
Optional<Long> any = cachedReaction.getUserInServersIds().stream().filter(user -> user.equals(userReacting.getUserInServerId())).findAny();
if(!any.isPresent()){
cachedReaction.getUserInServersIds().add(userReacting.getUserInServerId());
}
}
}
private void removeReactionIfThere(CachedMessage message, CachedReaction reaction, AUserInAServer userReacting) {
Optional<CachedReaction> existingReaction = message.getReactions().stream().filter(reaction1 ->
emoteService.compareAEmote(reaction1.getEmote(), reaction.getEmote())
).findAny();
if(existingReaction.isPresent()) {
CachedReaction cachedReaction = existingReaction.get();
cachedReaction.getUserInServersIds().removeIf(user -> user.equals(userReacting.getUserInServerId()));
message.getReactions().removeIf(reaction1 -> reaction1.getUserInServersIds().isEmpty());
}
}
@Transactional
public void callAddedListeners(@Nonnull GuildMessageReactionAddEvent event, CachedMessage cachedMessage, CachedReaction reaction) {
AUserInAServer userInAServer = userInServerManagementService.loadUser(event.getGuild().getIdLong(), event.getUserIdLong());
addReactionIfNotThere(cachedMessage, reaction, userInAServer);
addedListenerList.forEach(reactedAddedListener -> {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(reactedAddedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
return;
}
try {
self.executeIndividiualReactionAddedListener(event, cachedMessage, userInAServer, reactedAddedListener);
} catch (Exception e) {
log.warn(String.format("Failed to execute reaction added listener %s.", reactedAddedListener.getClass().getName()), e);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividiualReactionAddedListener(@Nonnull GuildMessageReactionAddEvent event, CachedMessage cachedMessage, AUserInAServer userInAServer, ReactedAddedListener reactedAddedListener) {
reactedAddedListener.executeReactionAdded(cachedMessage, event, userInAServer);
}
@Override
@Transactional
public void onGuildMessageReactionRemove(@Nonnull GuildMessageReactionRemoveEvent event) {
if(event.getUserIdLong() == botService.getInstance().getSelfUser().getIdLong()) {
return;
}
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
asyncMessageFromCache.thenAccept(cachedMessage -> {
messageCache.getCachedReactionFromReaction(event.getReaction()).thenAccept(reaction ->
self.callRemoveListeners(event, cachedMessage, reaction)
) .exceptionally(throwable -> {
log.error("Failed to retrieve cached reaction for message {} ", event.getMessageIdLong(), throwable);
return null;
});
messageCache.putMessageInCache(cachedMessage);
}).exceptionally(throwable -> {
log.error("Message retrieval {} from cache failed. ", event.getMessageIdLong(), throwable);
return null;
});
}
@Transactional
public void callRemoveListeners(@Nonnull GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, CachedReaction reaction) {
AUserInAServer userInAServer = userInServerManagementService.loadUser(event.getGuild().getIdLong(), event.getUserIdLong());
removeReactionIfThere(cachedMessage, reaction, userInAServer);
reactionRemovedListeners.forEach(reactionRemovedListener -> {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(reactionRemovedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
return;
}
try {
self.executeIndividualReactionRemovedListener(event, cachedMessage, userInAServer, reactionRemovedListener);
} catch (AbstractoRunTimeException e) {
log.warn(String.format("Failed to execute reaction removed listener %s.", reactionRemovedListener.getClass().getName()), e);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualReactionRemovedListener(@Nonnull GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, AUserInAServer userInAServer, ReactedRemovedListener reactionRemovedListener) {
reactionRemovedListener.executeReactionRemoved(cachedMessage, event, userInAServer);
}
@Transactional
public void callClearListeners(@Nonnull GuildMessageReactionRemoveAllEvent event, CachedMessage cachedMessage) {
clearedListenerList.forEach(reactionRemovedListener -> {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(reactionRemovedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
return;
}
try {
reactionRemovedListener.executeReactionCleared(cachedMessage);
} catch (AbstractoRunTimeException e) {
log.warn(String.format("Failed to execute reaction clear listener %s.", reactionRemovedListener.getClass().getName()), e);
}
});
}
@Override
@Transactional
public void onGuildMessageReactionRemoveAll(@Nonnull GuildMessageReactionRemoveAllEvent event) {
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
asyncMessageFromCache.thenAccept(cachedMessage -> {
cachedMessage.getReactions().clear();
messageCache.putMessageInCache(cachedMessage);
self.callClearListeners(event, cachedMessage);
}) .exceptionally(throwable -> {
log.error("Message retrieval from cache failed for message {}", event.getMessageIdLong(), throwable);
return null;
});
}
@PostConstruct
public void postConstruct() {
reactionRemovedListeners.sort(Comparator.comparing(Prioritized::getPriority).reversed());
addedListenerList.sort(Comparator.comparing(Prioritized::getPriority).reversed());
clearedListenerList.sort(Comparator.comparing(Prioritized::getPriority).reversed());
}
}

View File

@@ -0,0 +1,76 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.service.CacheEntityService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.emote.EmoteAddedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Service
@Slf4j
public class AsyncEmoteCreatedListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncEmoteCreatedListener> createdListeners;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureModeService featureModeService;
@Autowired
private AsyncEmoteCreatedListenerBean self;
@Autowired
@Qualifier("emoteCreatedExecutor")
private TaskExecutor emoteCreatedExecutor;
@Autowired
private CacheEntityService cacheEntityService;
@Override
@Transactional
public void onEmoteAdded(@NotNull EmoteAddedEvent event) {
if(createdListeners == null) return;
CachedEmote cachedEmote = cacheEntityService.getCachedEmoteFromEmote(event.getEmote(), event.getGuild());
createdListeners.forEach(emoteUpdatedListener ->
CompletableFuture.runAsync(() ->
self.executeCreatedListener(emoteUpdatedListener, cachedEmote, event.getGuild().getIdLong())
, emoteCreatedExecutor)
.exceptionally(throwable -> {
log.error("Async join listener {} failed with exception.", emoteUpdatedListener, throwable);
return null;
})
);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeCreatedListener(AsyncEmoteCreatedListener listener, CachedEmote createDdEmote, Long serverId) {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(listener.getFeature());
if (!featureFlagService.isFeatureEnabled(feature, serverId)) {
return;
}
if(!featureModeService.necessaryFeatureModesMet(listener, serverId)) {
return;
}
listener.emoteCreated(createDdEmote);
}
}

View File

@@ -0,0 +1,76 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.service.CacheEntityService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.emote.EmoteRemovedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Service
@Slf4j
public class AsyncEmoteDeletedListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncEmoteDeletedListener> deletedListeners;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureModeService featureModeService;
@Autowired
private AsyncEmoteDeletedListenerBean self;
@Autowired
@Qualifier("emoteDeletedExecutor")
private TaskExecutor emoteCreatedExecutor;
@Autowired
private CacheEntityService cacheEntityService;
@Override
public void onEmoteRemoved(@NotNull EmoteRemovedEvent event) {
if(deletedListeners == null) return;
CachedEmote cachedEmote = cacheEntityService.getCachedEmoteFromEmote(event.getEmote(), event.getGuild());
deletedListeners.forEach(emoteUpdatedListener ->
CompletableFuture.runAsync(() ->
self.executeDeletedListener(emoteUpdatedListener, cachedEmote, event.getGuild().getIdLong())
, emoteCreatedExecutor)
.exceptionally(throwable -> {
log.error("Async join listener {} failed with exception.", emoteUpdatedListener, throwable);
return null;
})
);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeDeletedListener(AsyncEmoteDeletedListener listener, CachedEmote deletedEmote, Long serverId) {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(listener.getFeature());
if (!featureFlagService.isFeatureEnabled(feature, serverId)) {
return;
}
if(!featureModeService.necessaryFeatureModesMet(listener, serverId)) {
return;
}
listener.emoteDeleted(deletedEmote);
}
}

View File

@@ -0,0 +1,76 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.service.CacheEntityService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.emote.update.EmoteUpdateNameEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Service
@Slf4j
public class AsyncEmoteUpdatedListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncEmoteUpdatedListener> updatedListeners;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureModeService featureModeService;
@Autowired
private AsyncEmoteUpdatedListenerBean self;
@Autowired
@Qualifier("emoteUpdatedExecutor")
private TaskExecutor emoteUpdatedExecutor;
@Autowired
private CacheEntityService cacheEntityService;
@Override
public void onEmoteUpdateName(@NotNull EmoteUpdateNameEvent event) {
if(updatedListeners == null) return;
CachedEmote cachedEmote = cacheEntityService.getCachedEmoteFromEmote(event.getEmote(), event.getGuild());
updatedListeners.forEach(emoteUpdatedListener ->
CompletableFuture.runAsync(() ->
self.executeUpdatedListener(emoteUpdatedListener, cachedEmote, event.getOldName(), event.getNewName(), event.getGuild().getIdLong())
, emoteUpdatedExecutor)
.exceptionally(throwable -> {
log.error("Async join listener {} failed with exception.", emoteUpdatedListener, throwable);
return null;
})
);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeUpdatedListener(AsyncEmoteUpdatedListener listener, CachedEmote updatedEmote, String oldName, String newName, Long serverId) {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(listener.getFeature());
if (!featureFlagService.isFeatureEnabled(feature, serverId)) {
return;
}
if(!featureModeService.necessaryFeatureModesMet(listener, serverId)) {
return;
}
listener.emoteUpdated(updatedEmote, oldName, newName);
}
}

View File

@@ -0,0 +1,78 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AsyncJoinListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncJoinListener> listenerList;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private AsyncJoinListenerBean self;
@Autowired
@Qualifier("joinListenerExecutor")
private TaskExecutor joinListenerExecutor;
@Override
@Transactional
public void onGuildMemberJoin(@Nonnull GuildMemberJoinEvent event) {
if(listenerList == null) return;
listenerList.forEach(joinListener -> {
ServerUser serverUser = ServerUser
.builder()
.serverId(event.getGuild().getIdLong())
.userId(event.getUser().getIdLong())
.build();
CompletableFuture.runAsync(() ->
self.executeIndividualJoinListener(joinListener, serverUser)
, joinListenerExecutor).exceptionally(throwable -> {
log.error("Async join listener {} failed with exception.", joinListener, throwable);
return null;
});
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualJoinListener(AsyncJoinListener joinListener, ServerUser serverUser) {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(joinListener.getFeature());
if (!featureFlagService.isFeatureEnabled(feature, serverUser.getServerId())) {
return;
}
log.trace("Executing async join listener {} for user {} in server {}.", joinListener, serverUser.getServerId(), serverUser.getUserId());
try {
joinListener.execute(serverUser);
} catch (Exception e) {
log.error("Listener {} failed with exception:", joinListener.getClass().getName(), e);
}
}
}

View File

@@ -0,0 +1,75 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AsyncLeaveListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncLeaveListener> listenerList;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
@Qualifier("leaveListenerExecutor")
private TaskExecutor leaveListenerExecutor;
@Autowired
private AsyncLeaveListenerBean self;
@Override
@Transactional
public void onGuildMemberRemove(@Nonnull GuildMemberRemoveEvent event) {
if(listenerList == null) return;
listenerList.forEach(leaveListener -> {
ServerUser serverUser = ServerUser
.builder()
.userId(event.getUser().getIdLong())
.serverId(event.getGuild().getIdLong())
.build();
CompletableFuture.runAsync(() ->
self.executeIndividualLeaveListener(serverUser, leaveListener)
, leaveListenerExecutor).exceptionally(throwable -> {
log.error("Async leave listener {} threw exception.", leaveListener, throwable);
return null;
});
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualLeaveListener(ServerUser user, AsyncLeaveListener leaveListener) {
log.trace("Executing leave listener {} for member {} in guild {}.", leaveListener.getClass().getName(), user.getUserId(), user.getServerId());
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(leaveListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, user.getServerId())) {
return;
}
try {
leaveListener.execute(user);
} catch (AbstractoRunTimeException e) {
log.error("Listener {} failed with exception:", leaveListener.getClass().getName(), e);
}
}
}

View File

@@ -0,0 +1,101 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.MessageCache;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.guild.GuildMessageDeleteEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
@Component
@Slf4j
public class AsyncMessageDeletedListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncMessageDeletedListener> listener;
@Autowired
private MessageCache messageCache;
@Autowired
private AsyncMessageDeletedListenerBean self;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private BotService botService;
@Autowired
@Qualifier("messageDeletedExecutor")
private TaskExecutor messageDeletedListenerExecutor;
@Override
@Transactional
public void onGuildMessageDelete(@Nonnull GuildMessageDeleteEvent event) {
if(listener == null) return;
Consumer<CachedMessage> cachedMessageConsumer = cachedMessage -> self.executeListener(cachedMessage);
messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong())
.thenAccept(cachedMessageConsumer)
.exceptionally(throwable -> {
log.error("Message retrieval {} from cache failed. ", event.getMessageIdLong(), throwable);
return null;
});
}
@Transactional
public void executeListener(CachedMessage cachedMessage) {
listener.forEach(messageDeletedListener ->
CompletableFuture.runAsync(() ->
self.executeIndividualMessageDeletedListener(cachedMessage, messageDeletedListener)
, messageDeletedListenerExecutor).exceptionally(throwable -> {
log.error("Async message deleted {} failed with exception.", messageDeletedListener, throwable);
return null;
})
);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualMessageDeletedListener(CachedMessage cachedMessage, AsyncMessageDeletedListener messageDeletedListener) {
log.trace("Executing message deleted listener {} for message {} in guild {}.", messageDeletedListener.getClass().getName(), cachedMessage.getMessageId(), cachedMessage.getMessageId());
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(messageDeletedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, cachedMessage.getServerId())) {
return;
}
try {
messageDeletedListener.execute(cachedMessage);
} catch (AbstractoRunTimeException e) {
log.error("Listener {} failed with exception:", messageDeletedListener.getClass().getName(), e);
}
}
}

View File

@@ -0,0 +1,91 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.command.service.ExceptionService;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.MessageCache;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.guild.GuildMessageEmbedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AsyncMessageEmbeddedListenerBean extends ListenerAdapter {
@Autowired
private MessageCache messageCache;
@Autowired(required = false)
private List<AsyncMessageEmbeddedListener> listenerList;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private BotService botService;
@Autowired
private ExceptionService exceptionService;
@Autowired
@Qualifier("messageEmbeddedExecutor")
private TaskExecutor messageEmbeddedListener;
@Autowired
private AsyncMessageEmbeddedListenerBean self;
@Override
public void onGuildMessageEmbed(@NotNull GuildMessageEmbedEvent event) {
if(listenerList == null) return;
GuildMessageEmbedEventModel model = buildModel(event);
listenerList.forEach(messageReceivedListener ->
CompletableFuture.runAsync(() ->
self.executeIndividualGuildMessageReceivedListener(model, messageReceivedListener)
, messageEmbeddedListener).exceptionally(throwable -> {
log.error("Async message embedded listener {} failed with exception.", messageReceivedListener, throwable);
return null;
})
);
}
private GuildMessageEmbedEventModel buildModel(GuildMessageEmbedEvent event) {
return GuildMessageEmbedEventModel
.builder()
.channelId(event.getChannel().getIdLong())
.serverId(event.getGuild().getIdLong())
.embeds(event.getMessageEmbeds())
.messageId(event.getMessageIdLong())
.build();
}
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE)
public void executeIndividualGuildMessageReceivedListener(GuildMessageEmbedEventModel model, AsyncMessageEmbeddedListener messageReceivedListener) {
try {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(messageReceivedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, model.getServerId())) {
return;
}
messageReceivedListener.execute(model);
} catch (Exception e) {
log.error("Listener {} had exception when executing.", messageReceivedListener, e);
}
}
}

View File

@@ -0,0 +1,78 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.command.service.ExceptionService;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.MessageCache;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AsyncMessageReceivedListenerBean extends ListenerAdapter {
@Autowired
private MessageCache messageCache;
@Autowired(required = false)
private List<AsyncMessageReceivedListener> listenerList;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private BotService botService;
@Autowired
private ExceptionService exceptionService;
@Autowired
@Qualifier("messageReceivedExecutor")
private TaskExecutor messageReceivedExecutor;
@Autowired
private AsyncMessageReceivedListenerBean self;
@Override
public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) {
if(listenerList == null) return;
messageCache.putMessageInCache(event.getMessage()).thenAccept(message -> {
for (AsyncMessageReceivedListener messageReceivedListener : listenerList) {
CompletableFuture.runAsync(() -> self.executeIndividualGuildMessageReceivedListener(message, messageReceivedListener), messageReceivedExecutor)
.exceptionally(throwable -> {
log.error("Async message received listener {} failed.", messageReceivedListener, throwable);
return null;
});
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualGuildMessageReceivedListener(CachedMessage cachedMessage, AsyncMessageReceivedListener messageReceivedListener) {
try {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(messageReceivedListener.getFeature());
if (!featureFlagService.isFeatureEnabled(feature, cachedMessage.getServerId())) {
return;
}
messageReceivedListener.execute(cachedMessage);
} catch (Exception e) {
log.error("Async listener {} had exception when executing.", messageReceivedListener, e);
}
}
}

View File

@@ -0,0 +1,83 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.MessageCache;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AsyncMessageUpdatedListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncMessageTextUpdatedListener> listener;
@Autowired
private MessageCache messageCache;
@Autowired
private AsyncMessageUpdatedListenerBean self;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
@Qualifier("messageUpdatedExecutor")
private TaskExecutor messageUpdatedExecutor;
@Override
public void onGuildMessageUpdate(GuildMessageUpdateEvent event) {
if(listener == null) return;
Message message = event.getMessage();
messageCache.getMessageFromCache(message.getGuild().getIdLong(), message.getTextChannel().getIdLong(), event.getMessageIdLong())
.thenAcceptBoth(messageCache.putMessageInCache(message), (oldCache, newCache) -> self.executeListener(newCache, oldCache))
.exceptionally(throwable -> {
log.error("Message retrieval {} from cache failed. ", event.getMessage().getId(), throwable);
return null;
});
}
@Transactional
public void executeListener(CachedMessage updatedMessage, CachedMessage oldMessage) {
listener.forEach(messageTextUpdatedListener ->
CompletableFuture
.runAsync(() -> self.executeIndividualMessageUpdatedListener(updatedMessage, oldMessage, messageTextUpdatedListener), messageUpdatedExecutor)
.exceptionally(throwable -> {
log.error("Async message receiver listener {} failed.", messageTextUpdatedListener, throwable);
return null;
})
);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualMessageUpdatedListener(CachedMessage updatedMessage, CachedMessage cachedMessage, AsyncMessageTextUpdatedListener messageTextUpdatedListener) {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(messageTextUpdatedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, cachedMessage.getServerId())) {
return;
}
try {
messageTextUpdatedListener.execute(cachedMessage, updatedMessage);
} catch (AbstractoRunTimeException e) {
log.error(String.format("Failed to execute listener. %s", messageTextUpdatedListener.getClass().getName()), e);
}
}
}

View File

@@ -0,0 +1,74 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.command.service.ExceptionService;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.CacheEntityService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AsyncPrivateMessageReceivedListenerBean extends ListenerAdapter {
@Autowired
private BotService botService;
@Autowired
private ExceptionService exceptionService;
@Autowired(required = false)
private List<AsyncPrivateMessageReceivedListener> privateMessageReceivedListeners;
@Autowired
private AsyncPrivateMessageReceivedListenerBean self;
@Autowired
private CacheEntityService cacheEntityService;
@Autowired
@Qualifier("privateMessageReceivedExecutor")
private TaskExecutor privateMessageReceivedExecutor;
@Override
public void onPrivateMessageReceived(@Nonnull PrivateMessageReceivedEvent event) {
if(privateMessageReceivedListeners == null) return;
if(event.getAuthor().getId().equals(botService.getInstance().getSelfUser().getId())) {
return;
}
cacheEntityService.buildCachedMessageFromMessage(event.getMessage()).thenAccept(cachedMessage ->
privateMessageReceivedListeners.forEach(messageReceivedListener -> {
try {
CompletableFuture.runAsync(() ->
self.executeIndividualPrivateMessageReceivedListener(cachedMessage, messageReceivedListener)
, privateMessageReceivedExecutor)
.exceptionally(throwable -> {
log.error("Async private message receiver listener {} failed.", messageReceivedListener, throwable);
return null;
});
} catch (Exception e) {
log.error("Private message received {} had exception when executing.", messageReceivedListener, e);
exceptionService.reportExceptionToPrivateMessageReceivedContext(e, event);
}
})
);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualPrivateMessageReceivedListener(CachedMessage cachedMessage, AsyncPrivateMessageReceivedListener messageReceivedListener) {
log.trace("Executing private message listener {} for member {}.", messageReceivedListener.getClass().getName(), cachedMessage.getAuthor().getAuthorId());
messageReceivedListener.execute(cachedMessage);
}
}

View File

@@ -0,0 +1,123 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReactions;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AsyncReactionAddedListenerBean extends ListenerAdapter {
@Autowired
private CacheEntityService cacheEntityService;
@Autowired
private MessageCache messageCache;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired(required = false)
private List<AsyncReactionAddedListener> addedListenerList;
@Autowired
private AsyncReactionAddedListenerBean self;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private BotService botService;
@Autowired
private EmoteService emoteService;
@Autowired
@Qualifier("reactionAddedExecutor")
private TaskExecutor reactionAddedTaskExecutor;
@Override
@Transactional
public void onGuildMessageReactionAdd(@Nonnull GuildMessageReactionAddEvent event) {
if(addedListenerList == null) return;
if(event.getUserIdLong() == botService.getInstance().getSelfUser().getIdLong()) {
return;
}
CompletableFuture<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
asyncMessageFromCache.thenAccept(cachedMessage ->
cacheEntityService.getCachedReactionFromReaction(event.getReaction()).thenAccept(reaction ->
self.callAddedListeners(event, cachedMessage, reaction)
).exceptionally(throwable -> {
log.error("Failed to handle add reaction to message {} ", event.getMessageIdLong(), throwable);
return null;
})
).exceptionally(throwable -> {
log.error("Message retrieval {} from cache failed. ", event.getMessageIdLong(), throwable);
return null;
});
}
private void addReactionIfNotThere(CachedMessage message, CachedReactions reaction, ServerUser userReacting) {
Optional<CachedReactions> existingReaction = message.getReactions().stream().filter(reaction1 ->
reaction1.getEmote().equals(reaction.getEmote())
).findAny();
if(!existingReaction.isPresent()) {
message.getReactions().add(reaction);
} else {
CachedReactions cachedReaction = existingReaction.get();
Optional<ServerUser> any = cachedReaction.getUsers().stream().filter(user -> user.getUserId().equals(userReacting.getUserId()) && user.getServerId().equals(userReacting.getServerId())).findAny();
if(!any.isPresent()){
cachedReaction.getUsers().add(userReacting);
}
}
}
@Transactional
public void callAddedListeners(@Nonnull GuildMessageReactionAddEvent event, CachedMessage cachedMessage, CachedReactions reaction) {
ServerUser serverUser = ServerUser.builder().serverId(event.getGuild().getIdLong()).userId(event.getUserIdLong()).build();
addReactionIfNotThere(cachedMessage, reaction, serverUser);
messageCache.putMessageInCache(cachedMessage);
addedListenerList.forEach(reactedAddedListener ->
CompletableFuture.runAsync(() ->
self.executeIndividualReactionAddedListener(reaction, cachedMessage, serverUser, reactedAddedListener)
, reactionAddedTaskExecutor)
.exceptionally(throwable -> {
log.error("Async reaction added listener {} failed with exception.", reactedAddedListener, throwable);
return null;
})
);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualReactionAddedListener(@Nonnull CachedReactions reaction, CachedMessage cachedMessage, ServerUser serverUser, AsyncReactionAddedListener reactedAddedListener) {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(reactedAddedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, serverUser.getServerId())) {
return;
}
try {
reactedAddedListener.executeReactionAdded(cachedMessage, reaction, serverUser);
} catch (Exception e) {
log.warn(String.format("Failed to execute reaction added listener %s.", reactedAddedListener.getClass().getName()), e);
}
}
}

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