[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.service.management.AssignableRolePlacePostManagementService;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
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.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,13 +15,13 @@ import java.util.Optional;
@Component
@Slf4j
public class AssignablePostDeletedListener implements MessageDeletedListener {
public class AssignablePostDeletedListener implements AsyncMessageDeletedListener {
@Autowired
private AssignableRolePlacePostManagementService service;
@Override
public void execute(CachedMessage messageBefore, AServerAChannelAUser authorUser, GuildChannelMember authorMember) {
public void execute(CachedMessage messageBefore) {
Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(messageBefore.getMessageId());
messageOptional.ifPresent(post -> {
AssignableRolePlace assignablePlace = post.getAssignablePlace();
@@ -39,8 +36,4 @@ public class AssignablePostDeletedListener implements MessageDeletedListener {
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.AssignedRoleUserManagementService;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.ReactedAddedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
import dev.sheldan.abstracto.core.models.ServerUser;
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.service.EmoteService;
import dev.sheldan.abstracto.core.service.ReactionService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
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.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
@@ -31,7 +33,7 @@ import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AssignablePostReactionAdded implements ReactedAddedListener {
public class AssignablePostReactionAdded implements AsyncReactionAddedListener {
@Autowired
private AssignableRolePlacePostManagementService service;
@@ -60,43 +62,49 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
@Autowired
private AssignableRoleManagementService assignableRoleManagementService;
@Autowired
private ReactionService reactionService;
@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());
if(messageOptional.isPresent()) {
MessageReaction reaction = event.getReaction();
AssignableRolePlacePost assignablePlacePost = messageOptional.get();
if(reaction.isSelf()) {
if(cachedReaction.getSelf()) {
log.info("Ignoring self reaction on assignable role post in server {}.", message.getServerId());
return;
}
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote();
CachedReaction specificReaction = cachedReaction.getReactionForSpecificUser(serverUser);
Long assignableRolePlaceId = assignablePlacePost.getId();
if(assignablePlacePost.getAssignablePlace().getActive()) {
log.info("User {} added reaction to assignable role place {} in server {}. Handling added event.", userAdding.getUserReference().getId(), assignablePlacePost.getId(), event.getGuild().getId());
addAppropriateRoles(event, reaction, assignablePlacePost, reactionEmote, userAdding);
log.info("User {} added reaction to assignable role place {} in server {}. Handling added event.", serverUser.getUserId(), assignablePlacePost.getId(), serverUser.getServerId());
addAppropriateRoles(specificReaction, assignablePlacePost, serverUser, message);
} else {
reaction.removeReaction(event.getUser()).submit();
log.trace("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), userAdding.getServerReference().getId());
reactionService.removeReactionFromMessage(specificReaction, message).exceptionally(throwable -> {
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;
AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (AssignableRole assignableRole : assignablePlacePost.getAssignableRoles()) {
log.trace("Checking emote {} if it was reaction for assignable role place.", assignableRole.getEmote().getId());
if (emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) {
if (emoteService.compareCachedEmoteWithAEmote(cachedReaction.getEmote(), assignableRole.getEmote())) {
if(assignableRolePlace.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles configured. Removing existing reactions and roles.", assignableRolePlace.getId());
Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(userAdding);
Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(serverUser);
byUserInServer.ifPresent(user -> futures.add(assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, user)));
}
Long assignableRoleId = assignableRole.getId();
log.info("User added {} reaction {} and gets assignable role {} in server {}.", userAdding.getUserReference().getId(), assignableRole.getEmote().getId(), assignableRoleId, userAdding.getServerReference().getId());
CompletableFuture<Void> roleAdditionFuture = assignableRoleServiceBean.assignAssignableRoleToUser(assignableRoleId, event.getMember());
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, serverUser);
futures.add(CompletableFuture.allOf(roleAdditionFuture));
validReaction = true;
@@ -105,23 +113,23 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
}
if(!validReaction) {
log.trace("Reaction was not found in the configuration of assignable role place {}, removing reaction.", assignableRolePlace.getId());
futures.add(reaction.removeReaction(event.getUser()).submit());
futures.add(reactionService.removeReactionFromMessage(cachedReaction, message));
}
Long assignableRolePlaceId = assignableRolePlace.getId();
Long userInServerId = userAdding.getUserInServerId();
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);
AUserInAServer userInAServer = userInServerManagementService.loadUser(userAdding);
AUserInAServer userInAServer = userInServerManagementService.loadUser(serverUser);
if(place.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles. Deleting all existing references.", assignableRolePlaceId);
assignableRoleServiceBean.clearAllRolesOfUserInPlace(place, userInAServer);
}
AssignableRole role = assignableRoleManagementService.getRoleForReactionEmote(reactionEmote, place);
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());
assignableRoleServiceBean.addRoleToUser(role.getId(), userInAServer);
@@ -132,8 +140,4 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
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.management.AssignableRolePlacePostManagementService;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.ReactedRemovedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionRemovedListener;
import dev.sheldan.abstracto.core.models.ServerUser;
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.RoleService;
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.stereotype.Component;
@@ -21,7 +19,7 @@ import java.util.Optional;
@Component
@Slf4j
public class AssignablePostReactionRemoved implements ReactedRemovedListener {
public class AssignablePostReactionRemoved implements AsyncReactionRemovedListener {
@Autowired
private AssignableRolePlacePostManagementService service;
@@ -41,31 +39,26 @@ public class AssignablePostReactionRemoved implements ReactedRemovedListener {
}
@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());
if(messageOptional.isPresent()) {
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote();
AssignableRolePlacePost assignablePlacePost = messageOptional.get();
if(assignablePlacePost.getAssignablePlace().getActive()) {
assignablePlacePost.getAssignableRoles().forEach(assignableRole -> {
if(emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) {
if(emoteService.compareCachedEmoteWithAEmote(reactions.getEmote(), assignableRole.getEmote())) {
Long assignableRoleId = assignableRole.getId();
log.info("Removing assignable role {} for user {} in server {} from assignable role place {}.", assignableRoleId,
userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), assignablePlacePost.getAssignablePlace().getId());
assignableRoleService.fullyRemoveAssignableRoleFromUser(assignableRole, event.getMember()).exceptionally(throwable -> {
log.error("Failed to remove assignable role {} from user {}.", assignableRoleId, event.getMember(), throwable);
userRemoving.getUserId(), userRemoving.getServerId(), assignablePlacePost.getAssignablePlace().getId());
assignableRoleService.fullyRemoveAssignableRoleFromUser(assignableRole, userRemoving).exceptionally(throwable -> {
log.error("Failed to remove assignable role {} from user {} in server {}.", assignableRoleId, userRemoving.getUserId(), userRemoving.getServerId(), throwable);
return null;
});
}
});
} 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.AssignedRoleUserManagementService;
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.service.BotService;
import dev.sheldan.abstracto.core.service.RoleService;
@@ -50,6 +51,11 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
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
public void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer userInAServer) {
AssignedRoleUser user = assignedRoleUserManagementServiceBean.findByUserInServer(userInAServer);
@@ -92,10 +98,11 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
}
@Override
public CompletableFuture<Void> fullyRemoveAssignableRoleFromUser(AssignableRole assignableRole, Member member) {
public CompletableFuture<Void> fullyRemoveAssignableRoleFromUser(AssignableRole assignableRole, ServerUser serverUser) {
Long assignableRoleId = assignableRole.getId();
return this.removeAssignableRoleFromUser(assignableRole, member).thenAccept(aVoid ->
self.persistRoleRemovalFromUser(assignableRoleId, member)
return botService.retrieveMemberInServer(serverUser).thenCompose(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.repository.AssignableRoleRepository;
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.ARole;
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.");
}
@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.AssignedRoleUser;
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.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -18,6 +20,9 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Autowired
private AssignedRoleUserRepository repository;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Override
public void addAssignedRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) {
Optional<AssignedRoleUser> optional = findByUserInServerOptional(aUserInAServer);
@@ -66,6 +71,12 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
return repository.findById(aUserInAServer.getUserInServerId());
}
@Override
public Optional<AssignedRoleUser> findByUserInServerOptional(ServerUser serverUser) {
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(serverUser);
return findByUserInServerOptional(aUserInAServer);
}
@Override
public AssignedRoleUser findByUserInServer(AUserInAServer 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"/>
</changeSet>
<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>
</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.AssignableRolePlace;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import net.dv8tion.jda.api.entities.Member;
@@ -9,12 +10,13 @@ import java.util.concurrent.CompletableFuture;
public interface AssignableRoleService {
CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member toAdd);
CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, ServerUser serverUser);
void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer user);
CompletableFuture<Void> fullyAssignAssignableRoleToUser(Long assignableRoleId, Member toAdd);
CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, Member member);
CompletableFuture<Void> removeAssignableRoleFromUser(Long assignableRoleId, Member member);
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(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.AssignableRolePlace;
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.ARole;
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 getByAssignableRoleId(Long assignableRoleId);
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.AssignedRoleUser;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import java.util.Optional;
@@ -13,5 +14,6 @@ public interface AssignedRoleUserManagementService {
void clearAllAssignedRolesOfUser(AUserInAServer userInAServer);
boolean doesAssignedRoleUserExist(AUserInAServer aUserInAServer);
Optional<AssignedRoleUser> findByUserInServerOptional(AUserInAServer aUserInAServer);
Optional<AssignedRoleUser> findByUserInServerOptional(ServerUser serverUser);
AssignedRoleUser findByUserInServer(AUserInAServer aUserInAServer);
}

View File

@@ -1,6 +1,6 @@
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.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;

View File

@@ -1,24 +1,24 @@
package dev.sheldan.abstracto.experience.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
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.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.config.features.ExperienceFeature;
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.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
* that a certain user has send a message, and experience should be awarded.
*/
@Component
public class ExperienceTrackerListener implements MessageReceivedListener {
@Slf4j
public class ExperienceTrackerListener implements AsyncMessageReceivedListener {
@Autowired
private AUserExperienceService userExperienceService;
@@ -27,9 +27,8 @@ public class ExperienceTrackerListener implements MessageReceivedListener {
private UserInServerManagementService userInServerManagementService;
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void execute(Message message) {
AUserInAServer cause = userInServerManagementService.loadUser(message.getMember());
public void execute(CachedMessage message) {
AUserInAServer cause = userInServerManagementService.loadUser(message.getServerId(), message.getAuthor().getAuthorId());
userExperienceService.addExperience(cause);
}
@@ -38,8 +37,4 @@ public class ExperienceTrackerListener implements MessageReceivedListener {
return ExperienceFeature.EXPERIENCE;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

@@ -1,15 +1,16 @@
package dev.sheldan.abstracto.experience.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.JoinListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncJoinListener;
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.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.config.features.ExperienceFeature;
import dev.sheldan.abstracto.experience.models.database.AUserExperience;
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
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.stereotype.Component;
@@ -20,7 +21,7 @@ import org.springframework.stereotype.Component;
*/
@Component
@Slf4j
public class JoiningUserRoleListener implements JoinListener {
public class JoiningUserRoleListener implements AsyncJoinListener {
@Autowired
private UserExperienceManagementService userExperienceManagementService;
@@ -28,17 +29,21 @@ public class JoiningUserRoleListener implements JoinListener {
@Autowired
private AUserExperienceService userExperienceService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Override
public void execute(Member member, Guild guild, AUserInAServer aUserInAServer) {
AUserExperience userExperience = userExperienceManagementService.findUserInServer(aUserInAServer);
Long userInServerId = aUserInAServer.getUserInServerId();
public void execute(ServerUser serverUser) {
AUserInAServer userInAServer = userInServerManagementService.loadUser(serverUser.getServerId(), serverUser.getUserId());
AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer);
Long userInServerId = userInAServer.getUserInServerId();
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 ->
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 {
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;
}
@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);
Integer level = (Integer) parameters.get(LEVEL_VARIABLE);
log.info("Evaluating has level condition.");
Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserConditional(userId);
Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserOptional(userId);
if(userInServerOptional.isPresent()) {
AUserInAServer userInServer = userInServerOptional.get();
log.info("Evaluating has level condition for user {} in server {} with level {}.",

View File

@@ -1,13 +1,13 @@
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.AUser;
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.service.AUserExperienceService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -31,13 +31,13 @@ public class ExperienceTrackerListenerTest extends ExperienceRelatedTest {
@Test
public void testExperienceTracking() {
AServer server = AServer.builder().id(3L).build();
AUser user = AUser.builder().id(4L).build();
AUserInAServer userInAServer = AUserInAServer.builder().userReference(user).serverReference(server).build();
Member member = Mockito.mock(Member.class);
Message mockedMessage = Mockito.mock(Message.class);
when(mockedMessage.getMember()).thenReturn(member);
when(userInServerManagementService.loadUser(member)).thenReturn(userInAServer);
AServer server = Mockito.mock(AServer.class);
AUser user = Mockito.mock(AUser.class);
AUserInAServer userInAServer = Mockito.mock(AUserInAServer.class);
CachedMessage mockedMessage = Mockito.mock(CachedMessage.class);
CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
when(mockedMessage.getAuthor()).thenReturn(cachedAuthor);
when(userInServerManagementService.loadUser(server.getId(), user.getId())).thenReturn(userInAServer);
testUnit.execute(mockedMessage);
verify(userExperienceService, times(1)).addExperience(userInAServer);
}

View File

@@ -1,14 +1,13 @@
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.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.ExperienceRelatedTest;
import dev.sheldan.abstracto.experience.models.database.AUserExperience;
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -32,31 +31,38 @@ public class JoiningUserRoleListenerTest extends ExperienceRelatedTest {
@Mock
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
public void testUserWithExperienceRejoining() {
AUser user = AUser.builder().id(1L).build();
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();
AUserExperience experience = Mockito.mock(AUserExperience.class);
when(userExperienceManagementService.findUserInServer(aUserInAServer)).thenReturn(experience);
when(userExperienceService.syncForSingleUser(experience)).thenReturn(CompletableFuture.completedFuture(null));
testUnit.execute(member, guild, aUserInAServer);
testUnit.execute(serverUser);
}
@Test
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);
testUnit.execute(member, guild, aUserInAServer);
verify(userExperienceService, times(0)).syncForSingleUser(experience);
testUnit.execute(serverUser);
verify(userExperienceService, times(0)).syncForSingleUser(any());
}
}

View File

@@ -1,26 +1,30 @@
package dev.sheldan.abstracto.moderation.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
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.listener.async.jda.AsyncMessageDeletedListener;
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.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.MessageDeletedLog;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
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.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
@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_ATTACHMENT_TEMPLATE = "message_deleted_attachment";
@@ -34,36 +38,52 @@ public class MessageDeleteLogListener implements MessageDeletedListener {
@Autowired
private PostTargetService postTargetService;
@Autowired
private BotService botService;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private MessageDeleteLogListener self;
@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());
TextChannel textChannel = botService.getTextChannelFromServer(messageFromCache.getServerId(), messageFromCache.getChannelId());
MessageDeletedLog logModel = MessageDeletedLog
.builder()
.cachedMessage(messageFromCache)
.server(authorUser.getGuild())
.channel(authorUser.getChannel())
.user(authorUser.getUser())
.aUserInAServer(authorUser.getAUserInAServer())
.guild(authorMember.getGuild())
.messageChannel(authorMember.getTextChannel())
.member(authorMember.getMember())
.channel(textChannel)
.member(authorMember)
.build();
MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_DELETED_TEMPLATE, logModel);
postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId());
if(messageFromCache.getAttachmentUrls() != null){
log.trace("Notifying about deletions of {} attachments.", messageFromCache.getAttachmentUrls().size());
for (int i = 0; i < messageFromCache.getAttachmentUrls().size(); i++) {
if(messageFromCache.getAttachments() != null){
log.trace("Notifying about deletions of {} attachments.", messageFromCache.getAttachments().size());
for (int i = 0; i < messageFromCache.getAttachments().size(); i++) {
MessageDeletedAttachmentLog log = MessageDeletedAttachmentLog
.builder()
.imageUrl(messageFromCache.getAttachmentUrls().get(i))
.imageUrl(messageFromCache.getAttachments().get(i).getProxyUrl())
.counter(i + 1)
.server(authorUser.getGuild())
.channel(authorUser.getChannel())
.user(authorUser.getUser())
.aUserInAServer(authorUser.getAUserInAServer())
.guild(authorMember.getGuild())
.messageChannel(authorMember.getTextChannel())
.member(authorMember.getMember())
.channel(textChannel)
.member(authorMember)
.build();
MessageToSend attachmentEmbed = templateService.renderEmbedTemplate(MESSAGE_DELETED_ATTACHMENT_TEMPLATE, log);
postTargetService.sendEmbedInPostTarget(attachmentEmbed, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId());
@@ -76,8 +96,4 @@ public class MessageDeleteLogListener implements MessageDeletedListener {
return ModerationFeatures.LOGGING;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

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

View File

@@ -1,13 +1,12 @@
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.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;
import dev.sheldan.abstracto.moderation.config.features.WarningDecayFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component

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.ListenerPriority;
import dev.sheldan.abstracto.core.listener.JoinListener;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncJoinListener;
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.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.templating.service.TemplateService;
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.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
@Service
@Slf4j
public class JoinLogger implements JoinListener {
public class JoinLogger implements AsyncJoinListener {
public static final String USER_JOIN_TEMPLATE = "user_join";
@@ -29,6 +29,11 @@ public class JoinLogger implements JoinListener {
@Autowired
private PostTargetService postTargetService;
@Autowired
private BotService botService;
@Autowired
private JoinLogger self;
private HashMap<String, Object> getUserParameter(User user) {
HashMap<String, Object> parameters = new HashMap<>();
@@ -37,11 +42,18 @@ public class JoinLogger implements JoinListener {
}
@Override
public void execute(Member member, Guild guild, AUserInAServer aUserInAServer) {
log.info("User {} joined server {}.", aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
public void execute(ServerUser serverUser) {
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());
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
@@ -49,8 +61,4 @@ public class JoinLogger implements JoinListener {
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.ListenerPriority;
import dev.sheldan.abstracto.core.listener.JoinListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncJoinListener;
import dev.sheldan.abstracto.core.models.ServerUser;
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.service.MuteService;
import dev.sheldan.abstracto.moderation.service.management.MuteManagementService;
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.stereotype.Component;
@Component
@Slf4j
public class JoinMuteListener implements JoinListener {
public class JoinMuteListener implements AsyncJoinListener {
@Autowired
private MuteManagementService muteManagementService;
@@ -23,10 +22,14 @@ public class JoinMuteListener implements JoinListener {
@Autowired
private MuteService muteService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@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)) {
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);
}
}
@@ -36,8 +39,4 @@ public class JoinMuteListener implements JoinListener {
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.ListenerPriority;
import dev.sheldan.abstracto.core.listener.LeaveListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncLeaveListener;
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.moderation.config.features.ModerationFeatures;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.templating.service.TemplateService;
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.User;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.HashMap;
@Service
@Slf4j
public class LeaveLogger implements LeaveListener {
public class LeaveLogger implements AsyncLeaveListener {
public static final String USER_LEAVE_TEMPLATE = "user_leave";
@@ -30,6 +31,11 @@ public class LeaveLogger implements LeaveListener {
@Autowired
private PostTargetService postTargetService;
@Autowired
private BotService botService;
@Autowired
private LeaveLogger self;
@NotNull
private HashMap<String, Object> getUserParameter(@Nonnull User user) {
@@ -40,10 +46,17 @@ public class LeaveLogger implements LeaveListener {
}
@Override
public void execute(Member member, Guild guild) {
log.info("User {} left server {}.", member.getUser().getId(), guild.getIdLong());
public void execute(ServerUser serverUser) {
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()));
postTargetService.sendTextInPostTarget(text, LoggingPostTarget.LEAVE_LOG, guild.getIdLong());
postTargetService.sendTextInPostTarget(text, LoggingPostTarget.LEAVE_LOG, serverUser.getServerId());
}
@Override
@@ -51,8 +64,4 @@ public class LeaveLogger implements LeaveListener {
return ModerationFeatures.LOGGING;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

@@ -268,15 +268,11 @@ public class MuteServiceBean implements MuteService {
throw new NoMuteFoundException();
}
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();
CompletableFuture<Member> mutingMemberFuture = botService.getMemberInServerAsync(mute.getMutingUser());
CompletableFuture<Member> mutedMemberFuture = botService.getMemberInServerAsync(mute.getMutedUser());
Guild guild = botService.getGuildById(mute.getServer().getId());
return endMute(mute).thenCompose(unused ->
Guild guild = botService.getGuildById(mute.getMuteId().getServerId());
return endMute(mute, false).thenCompose(unused ->
CompletableFuture.allOf(mutingMemberFuture, mutedMemberFuture)
).thenCompose(unused -> self.sendUnMuteLogForManualUnMute(muteId, mutingMemberFuture, mutedMemberFuture, guild));
}
@@ -296,7 +292,11 @@ public class MuteServiceBean implements MuteService {
}
@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();
AServer mutingServer = mute.getServer();
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<Void> finalFuture = new CompletableFuture<>();
CompletableFuture.allOf(mutingMemberFuture, mutedMemberFuture, roleRemovalFuture, mutingMemberFuture, mutedMemberFuture).handle((aVoid, throwable) -> {
self.sendUnmuteLog(muteId, guild, mutingMemberFuture, mutedMemberFuture).thenAccept(aVoid1 ->
finalFuture.complete(null)
);
if(sendNotification) {
self.sendUnmuteLog(muteId, guild, mutingMemberFuture, mutedMemberFuture).thenAccept(aVoid1 ->
finalFuture.complete(null)
);
} else {
finalFuture.complete(null);
}
return null;
});
@@ -357,7 +361,7 @@ public class MuteServiceBean implements MuteService {
log.info("UnMuting the mute {} in server {}", muteId, serverId);
Optional<Mute> muteOptional = muteManagementService.findMuteOptional(muteId, serverId);
if(muteOptional.isPresent()) {
return endMute(muteOptional.get());
return endMute(muteOptional.get(), true);
} else {
throw new NoMuteFoundException();
}

View File

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

View File

@@ -1,6 +1,9 @@
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.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.moderation.listener.async.JoinMuteListener;
import dev.sheldan.abstracto.moderation.service.MuteService;
import dev.sheldan.abstracto.moderation.service.management.MuteManagementService;
import net.dv8tion.jda.api.entities.Guild;
@@ -25,6 +28,9 @@ public class JoinMuteListenerTest {
@Mock
private MuteService muteService;
@Mock
private UserInServerManagementService userInServerManagementService;
@Mock
private Member member;
@@ -34,17 +40,29 @@ public class JoinMuteListenerTest {
@Mock
private AUserInAServer joiningUser;
@Mock
private ServerUser serverUser;
private static final Long SERVER_ID = 3L;
private static final Long USER_ID = 4L;
@Test
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);
testUnit.execute(member, guild, joiningUser);
testUnit.execute(serverUser);
verify(muteService, times(0)).applyMuteRole(joiningUser);
}
@Test
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);
testUnit.execute(member, guild, joiningUser);
testUnit.execute(serverUser);
verify(muteService, times(1)).applyMuteRole(joiningUser);
}
}

View File

@@ -1,9 +1,11 @@
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.moderation.config.posttargets.LoggingPostTarget;
import dev.sheldan.abstracto.moderation.listener.async.LeaveLogger;
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.User;
import org.junit.Test;
@@ -13,6 +15,8 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
@@ -27,18 +31,39 @@ public class LeaveLoggerTest {
@Mock
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
public void executeListener() {
Member leavingMember = Mockito.mock(Member.class);
Guild guild = Mockito.mock(Guild.class);
User user = Mockito.mock(User.class);
when(leavingMember.getUser()).thenReturn(user);
Long guildId = 6L;
when(guild.getIdLong()).thenReturn(guildId);
when(member.getUser()).thenReturn(user);
String message = "text";
when(leavingUser.getServerId()).thenReturn(SERVER_ID);
when(templateService.renderTemplateWithMap(eq(LeaveLogger.USER_LEAVE_TEMPLATE), any())).thenReturn(message);
testUnit.execute(leavingMember, guild);
verify(postTargetService, times(1)).sendTextInPostTarget(message, LoggingPostTarget.LEAVE_LOG, guildId);
testUnit.executeJoinLogging(leavingUser, member);
verify(postTargetService, times(1)).sendTextInPostTarget(message, LoggingPostTarget.LEAVE_LOG, SERVER_ID);
}
}

View File

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

View File

@@ -1,6 +1,8 @@
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.service.BotService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.posttargets.LoggingPostTarget;
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 net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import org.junit.Assert;
import org.junit.Test;
@@ -19,6 +20,8 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
@@ -34,15 +37,22 @@ public class MessageEditedListenerTest {
private PostTargetService postTargetService;
@Mock
private Message messageAfter;
private BotService botService;
@Mock
private CachedMessage messageAfter;
@Mock
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
public void testExecuteListenerWithSameContent() {
String content = "text";
when(messageAfter.getContentRaw()).thenReturn(content);
when(messageAfter.getContent()).thenReturn(content);
when(messageBefore.getContent()).thenReturn(content);
testUnit.execute(messageBefore, messageAfter);
verify(templateService, times(0)).renderEmbedTemplate(eq(MessageEditedListener.MESSAGE_EDITED_TEMPLATE), any());
@@ -53,25 +63,29 @@ public class MessageEditedListenerTest {
String content = "text";
String contentAfterwards = "text2";
TextChannel channel = Mockito.mock(TextChannel.class);
Long serverId = 5L;
when(messageAfter.getContentRaw()).thenReturn(contentAfterwards);
when(messageAfter.getTextChannel()).thenReturn(channel);
when(messageAfter.getContent()).thenReturn(contentAfterwards);
when(messageAfter.getChannelId()).thenReturn(CHANNEL_ID);
Guild guild = Mockito.mock(Guild.class);
when(messageAfter.getGuild()).thenReturn(guild);
Member member = Mockito.mock(Member.class);
when(messageAfter.getMember()).thenReturn(member);
when(channel.getGuild()).thenReturn(guild);
when(messageAfter.getServerId()).thenReturn(SERVER_ID);
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.getServerId()).thenReturn(serverId);
when(messageBefore.getServerId()).thenReturn(SERVER_ID);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
ArgumentCaptor<MessageEditedLog> captor = ArgumentCaptor.forClass(MessageEditedLog.class);
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);
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();
Assert.assertEquals(messageBefore, capturedValue.getMessageBefore());
Assert.assertEquals(messageAfter, capturedValue.getMessageAfter());
Assert.assertEquals(channel, capturedValue.getMessageChannel());
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.getAMuteOf(userBeingMuted)).thenReturn(mute);
when(mute.getMuteId()).thenReturn(new ServerSpecificId(SERVER_ID, MUTE_ID));
when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
testUnit.unMuteUser(userBeingMuted);
verifyNoUnMuteHappened();
}

View File

@@ -1,6 +1,6 @@
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.Setter;
import lombok.experimental.SuperBuilder;
@@ -12,7 +12,7 @@ import lombok.experimental.SuperBuilder;
@Getter
@Setter
@SuperBuilder
public class MessageDeletedAttachmentLog extends UserInitiatedServerContext {
public class MessageDeletedAttachmentLog extends SlimUserInitiatedServerContext {
/**
* The proxy URL to the attachment which was deleted.
*/

View File

@@ -1,7 +1,7 @@
package dev.sheldan.abstracto.moderation.models.template.listener;
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.Setter;
import lombok.experimental.SuperBuilder;
@@ -12,7 +12,7 @@ import lombok.experimental.SuperBuilder;
@Getter
@Setter
@SuperBuilder
public class MessageDeletedLog extends UserInitiatedServerContext {
public class MessageDeletedLog extends SlimUserInitiatedServerContext {
/**
* 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.Setter;
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"
@@ -15,9 +14,9 @@ import net.dv8tion.jda.api.entities.Message;
@SuperBuilder
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

View File

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

View File

@@ -1,6 +1,6 @@
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.service.management.ConfigManagementService;
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;

View File

@@ -1,10 +1,7 @@
package dev.sheldan.abstracto.modmail.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
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.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.MessageService;
@@ -22,7 +19,7 @@ import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class ModMailMessageDeletedListener implements MessageDeletedListener {
public class ModMailMessageDeletedListener implements AsyncMessageDeletedListener {
@Autowired
private ModMailMessageManagementService modMailMessageManagementService;
@@ -37,7 +34,7 @@ public class ModMailMessageDeletedListener implements MessageDeletedListener {
private BotService botService;
@Override
public void execute(CachedMessage messageBefore, AServerAChannelAUser authorUser, GuildChannelMember authorMember) {
public void execute(CachedMessage messageBefore) {
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageBefore.getMessageId());
messageOptional.ifPresent(modMailMessage -> {
ModMailThread thread = modMailMessage.getThreadReference();
@@ -76,8 +73,4 @@ public class ModMailMessageDeletedListener implements MessageDeletedListener {
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.CommandService;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.MessageTextUpdatedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageTextUpdatedListener;
import dev.sheldan.abstracto.core.models.FullUserInServer;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel;
@@ -32,7 +31,7 @@ import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class ModMailMessageEditedListener implements MessageTextUpdatedListener {
public class ModMailMessageEditedListener implements AsyncMessageTextUpdatedListener {
public static final String DEFAULT_COMMAND_FOR_MODMAIL_EDIT = "reply";
@Autowired
@@ -63,32 +62,40 @@ public class ModMailMessageEditedListener implements MessageTextUpdatedListener
private ModMailThreadService modMailThreadService;
@Override
public void execute(CachedMessage messageBefore, Message messageAfter) {
public void execute(CachedMessage messageBefore, CachedMessage messageAfter) {
if(!modMailThreadService.isModMailThread(messageBefore.getChannelId())) {
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());
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());
String contentStripped = messageAfter.getContentRaw();
String contentStripped = messageAfter.getContent();
String commandName = commandRegistry.getCommandName(contentStripped.substring(0, contentStripped.indexOf(" ")), messageBefore.getServerId());
if(!commandService.doesCommandExist(commandName)) {
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);
}
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> loadEditingUser = botService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getAuthor().getUserReference().getId());
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
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);
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(messageAfter.getIdLong());
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(loadedMessage.getIdLong());
messageOptional.ifPresent(modMailMessage -> {
FullUserInServer fullThreadUser = FullUserInServer
.builder()
@@ -99,7 +106,7 @@ public class ModMailMessageEditedListener implements MessageTextUpdatedListener
.builder()
.text(newText)
.modMailThread(modMailMessage.getThreadReference())
.postedMessage(messageAfter)
.postedMessage(loadedMessage)
.anonymous(modMailMessage.getAnonymous())
.threadUser(fullThreadUser);
if(modMailMessage.getAnonymous()) {
@@ -122,7 +129,7 @@ public class ModMailMessageEditedListener implements MessageTextUpdatedListener
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.",
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;
}
@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.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.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserManagementService;

View File

@@ -1,7 +1,5 @@
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.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
@@ -47,12 +45,6 @@ public class ModMailMessageDeletedListenerTest {
@Mock
private CachedMessage deletedMessage;
@Mock
private AServerAChannelAUser origin;
@Mock
private GuildChannelMember jdaOrigin;
@Mock
private ModMailMessage modMailMessage;
@@ -79,7 +71,7 @@ public class ModMailMessageDeletedListenerTest {
public void testDeleteOutSideOfThread() {
when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.empty());
testUnit.execute(deletedMessage, origin, jdaOrigin);
testUnit.execute(deletedMessage);
verify(botService, times(0)).getMemberInServerAsync(anyLong(), anyLong());
}
@@ -102,7 +94,7 @@ public class ModMailMessageDeletedListenerTest {
when(targetMember.getUser()).thenReturn(targetUser);
when(botService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
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(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(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));
testUnit.execute(deletedMessage, origin, jdaOrigin);
testUnit.execute(deletedMessage);
verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID);
}

View File

@@ -73,7 +73,10 @@ public class ModMailMessageEditedListenerTest {
private CachedMessage messageBefore;
@Mock
private Message messageAfter;
private CachedMessage messageAfter;
@Mock
private Message loadedMessage;
@Mock
private ModMailMessage modMailMessage;
@@ -109,6 +112,15 @@ public class ModMailMessageEditedListenerTest {
private static final Long USER_ID = 3L;
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
public void testEditOutsideModMailThread() {
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(false);
@@ -119,17 +131,14 @@ public class ModMailMessageEditedListenerTest {
@Test
public void testEditNotTrackedMessage() {
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.empty());
testUnit.execute(messageBefore, messageAfter);
testUnit.executeMessageUpdatedLogic(messageBefore, messageAfter, loadedMessage);
verify(commandRegistry, times(0)).getCommandName(anyString(), anyLong());
}
@Test
public void testEditMessageWithCorrectCommand() {
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
when(messageBefore.getServerId()).thenReturn(SERVER_ID);
@@ -146,19 +155,18 @@ public class ModMailMessageEditedListenerTest {
AUser authorUser = Mockito.mock(AUser.class);
when(authorUser.getId()).thenReturn(AUTHOR_USER_ID);
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(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, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
testUnit.execute(messageBefore, messageAfter);
verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember);
testUnit.executeMessageUpdatedLogic(messageBefore, messageAfter, loadedMessage);
verify(self, times(1)).updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
}
@Test
public void testEditMessageWithInCorrectCommand() {
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
when(messageBefore.getServerId()).thenReturn(SERVER_ID);
@@ -175,19 +183,19 @@ public class ModMailMessageEditedListenerTest {
AUser authorUser = Mockito.mock(AUser.class);
when(authorUser.getId()).thenReturn(AUTHOR_USER_ID);
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(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, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
testUnit.execute(messageBefore, messageAfter);
verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember);
testUnit.executeMessageUpdatedLogic(messageBefore, messageAfter, loadedMessage);
verify(self, times(1)).updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
}
@Test
public void testUpdateAnonymousMessageInThreadNotDuplicated() {
when(messageAfter.getIdLong()).thenReturn(MESSAGE_ID);
public void testUpdateAnonymousMessageInThreadNotSentToModMailThreadChannel() {
when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
when(modMailMessage.getAnonymous()).thenReturn(true);
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
@@ -199,15 +207,15 @@ public class ModMailMessageEditedListenerTest {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
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(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous());
}
@Test
public void testUpdateAnonymousMessageInThreadDuplicated() {
when(messageAfter.getIdLong()).thenReturn(MESSAGE_ID);
public void testUpdateAnonymousMessageInThreadAlsoSendToModMailThreadChannel() {
when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
when(modMailMessage.getAnonymous()).thenReturn(true);
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID);
@@ -220,9 +228,10 @@ public class ModMailMessageEditedListenerTest {
AChannel channel = Mockito.mock(AChannel.class);
when(thread.getChannel()).thenReturn(channel);
when(channel.getId()).thenReturn(CHANNEL_ID);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
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(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous());
@@ -230,7 +239,7 @@ public class ModMailMessageEditedListenerTest {
@Test
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(modMailMessage.getAnonymous()).thenReturn(false);
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
@@ -242,7 +251,7 @@ public class ModMailMessageEditedListenerTest {
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
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(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous());
@@ -250,7 +259,7 @@ public class ModMailMessageEditedListenerTest {
@Test
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(modMailMessage.getAnonymous()).thenReturn(false);
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID);
@@ -265,7 +274,7 @@ public class ModMailMessageEditedListenerTest {
when(channel.getId()).thenReturn(CHANNEL_ID);
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
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(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
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.FeatureMode;
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.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
@@ -22,16 +23,15 @@ import java.util.List;
*/
@Component
@Slf4j
public class CreateTrackedEmoteListener implements EmoteCreatedListener {
public class CreateTrackedEmoteListener implements AsyncEmoteCreatedListener {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Override
public void emoteCreated(Emote 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.getGuild().getIdLong(), createdEmote.getIdLong());
trackedEmoteManagementService.createTrackedEmote(createdEmote, createdEmote.getGuild());
public void emoteCreated(CachedEmote createdEmote) {
log.info("Creating tracked emote {} in server {}.", createdEmote.getServerId(), createdEmote.getEmoteId());
trackedEmoteManagementService.createTrackedEmote(createdEmote);
}
@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.FeatureMode;
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.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
@@ -22,15 +23,15 @@ import java.util.List;
*/
@Component
@Slf4j
public class DeleteTrackedEmoteListener implements EmoteDeletedListener {
public class DeleteTrackedEmoteListener implements AsyncEmoteDeletedListener {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Override
public void emoteDeleted(Emote deletedEmote) {
log.info("Marking tracked emote {} in gild {} as deleted.", deletedEmote.getId(), deletedEmote.getGuild().getIdLong());
trackedEmoteManagementService.markAsDeleted(deletedEmote.getGuild().getIdLong(), deletedEmote.getIdLong());
public void emoteDeleted(CachedEmote deletedEmote) {
log.info("Marking tracked emote {} in gild {} as deleted.", deletedEmote.getEmoteId(), deletedEmote.getServerId());
trackedEmoteManagementService.markAsDeleted(deletedEmote.getServerId(), deletedEmote.getEmoteId());
}
@Override

View File

@@ -1,14 +1,12 @@
package dev.sheldan.abstracto.statistic.emotes.listener;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
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.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.stereotype.Component;
@@ -21,17 +19,19 @@ import java.util.stream.Collectors;
* the runtime storage for emote tracking.
*/
@Component
public class EmoteTrackingListener implements MessageReceivedListener {
public class EmoteTrackingListener implements AsyncMessageReceivedListener {
@Autowired
private TrackedEmoteService trackedEmoteService;
@Autowired
private BotService botService;
@Override
public void execute(Message message) {
Bag<Emote> emotesBag = message.getEmotesBag();
Map<Long, List<Emote>> collect = emotesBag.stream().collect(Collectors.groupingBy(ISnowflake::getIdLong));
public void execute(CachedMessage message) {
Map<Long, List<CachedEmote>> collect = message.getEmotes().stream().collect(Collectors.groupingBy(CachedEmote::getEmoteId));
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;
}
@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.FeatureMode;
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.emotes.config.EmoteTrackingMode;
import dev.sheldan.abstracto.statistic.emotes.model.database.TrackedEmote;
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.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.
*/
@Component
public class UpdateTrackedEmoteListener implements EmoteUpdatedListener {
public class UpdateTrackedEmoteListener implements AsyncEmoteUpdatedListener {
@Autowired
private TrackedEmoteManagementService trackedEmoteManagementService;
@Override
public void emoteUpdated(Emote updatedEmote, String oldValue, String newValue) {
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByEmote(updatedEmote);
public void emoteUpdated(CachedEmote updatedEmote, String oldValue, String newValue) {
TrackedEmote trackedEmote = trackedEmoteManagementService.loadByEmoteId(updatedEmote.getEmoteId(), updatedEmote.getServerId());
trackedEmoteManagementService.changeName(trackedEmote, newValue);
}

View File

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

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.service;
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.EmoteService;
import dev.sheldan.abstracto.core.service.FeatureModeService;
@@ -48,24 +49,22 @@ public class TrackedEmoteServiceBean implements TrackedEmoteService {
private BotService botService;
@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);
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)
if(externalTrackingEnabled || emoteIsFromGuild) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, !emoteIsFromGuild);
if(externalTrackingEnabled || !emote.getExternal()) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, emote.getExternal());
}
});
}
@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 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)
if(externalTrackingEnabled || emoteIsFromGuild) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, !emoteIsFromGuild);
if(externalTrackingEnabled || !emote.getExternal()) {
trackedEmoteRuntimeService.addEmoteForServer(emote, guild, count, emote.getExternal());
}
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.service.management;
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.service.management.ServerManagementService;
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);
}
@Override
public TrackedEmote createTrackedEmote(CachedEmote emote) {
AServer server = serverManagementService.loadServer(emote.getServerId());
return createTrackedEmote(emote.getEmoteId(), emote.getEmoteName(), emote.getAnimated(), true, server);
}
@Override
public TrackedEmote createTrackedEmote(Emote emote, Guild guild, boolean external) {
if(external) {

View File

@@ -1,10 +1,9 @@
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.statistic.config.StatisticFeatures;
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.Test;
import org.junit.runner.RunWith;
@@ -28,13 +27,11 @@ public class CreateTrackedEmoteListenerTest {
public void testEmoteCreated() {
Long serverId = 4L;
Long emoteId = 5L;
Emote emote = Mockito.mock(Emote.class);
Guild guild = Mockito.mock(Guild.class);
when(guild.getIdLong()).thenReturn(serverId);
when(emote.getIdLong()).thenReturn(emoteId);
when(emote.getGuild()).thenReturn(guild);
CachedEmote emote = Mockito.mock(CachedEmote.class);
when(emote.getEmoteId()).thenReturn(emoteId);
when(emote.getServerId()).thenReturn(serverId);
testUnit.emoteCreated(emote);
verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote, guild);
verify(trackedEmoteManagementService, times(1)).createTrackedEmote(emote);
}
@Test

View File

@@ -1,10 +1,9 @@
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.statistic.config.StatisticFeatures;
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.Test;
import org.junit.runner.RunWith;
@@ -28,11 +27,9 @@ public class DeleteTrackedEmoteListenerTest {
public void testEmoteDeleted() {
Long serverId = 4L;
Long emoteId = 5L;
Emote emote = Mockito.mock(Emote.class);
Guild guild = Mockito.mock(Guild.class);
when(guild.getIdLong()).thenReturn(serverId);
when(emote.getIdLong()).thenReturn(emoteId);
when(emote.getGuild()).thenReturn(guild);
CachedEmote emote = Mockito.mock(CachedEmote.class);
when(emote.getEmoteId()).thenReturn(emoteId);
when(emote.getServerId()).thenReturn(serverId);
testUnit.emoteDeleted(emote);
verify(trackedEmoteManagementService, times(1)).markAsDeleted(serverId, emoteId);
}

View File

@@ -1,12 +1,11 @@
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.emotes.service.TrackedEmoteService;
import net.dv8tion.jda.api.entities.Emote;
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.Test;
import org.junit.runner.RunWith;
@@ -14,6 +13,9 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
@@ -26,51 +28,58 @@ public class EmoteTrackingListenerTest {
private TrackedEmoteService trackedEmoteService;
@Mock
private Message message;
private BotService botService;
@Mock
private Emote emote1;
private CachedMessage message;
@Mock
private Emote emote2;
private CachedEmote emote1;
@Mock
private CachedEmote emote2;
@Mock
private Guild guild;
private static final Long EMOTE_ID = 4L;
private static final Long SERVER_ID = 3L;
@Test
public void testExecuteOneEmote() {
HashBag<Emote> emotesBag = new HashBag<>();
List<CachedEmote> emotesBag = new ArrayList<>();
emotesBag.add(emote1);
when(message.getGuild()).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag);
when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getEmotes()).thenReturn(emotesBag);
testUnit.execute(message);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L);
}
@Test
public void testExecuteOneEmoteMultipleTimes() {
HashBag<Emote> emotesBag = new HashBag<>();
when(emote1.getIdLong()).thenReturn(EMOTE_ID);
when(emote2.getIdLong()).thenReturn(EMOTE_ID);
List<CachedEmote> emotesBag = new ArrayList<>();
when(emote1.getEmoteId()).thenReturn(EMOTE_ID);
when(emote2.getEmoteId()).thenReturn(EMOTE_ID);
emotesBag.add(emote1);
emotesBag.add(emote2);
when(message.getGuild()).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag);
when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getEmotes()).thenReturn(emotesBag);
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
public void testExecuteMultipleEmotes() {
HashBag<Emote> emotesBag = new HashBag<>();
when(emote1.getIdLong()).thenReturn(EMOTE_ID);
when(emote2.getIdLong()).thenReturn(EMOTE_ID + 1);
List<CachedEmote> emotesBag = new ArrayList<>();
when(emote1.getEmoteId()).thenReturn(EMOTE_ID);
when(emote2.getEmoteId()).thenReturn(EMOTE_ID + 1);
emotesBag.add(emote1);
emotesBag.add(emote2);
when(message.getGuild()).thenReturn(guild);
when(message.getEmotesBag()).thenReturn(emotesBag);
when(botService.getGuildById(SERVER_ID)).thenReturn(guild);
when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getEmotes()).thenReturn(emotesBag);
testUnit.execute(message);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote1, guild, 1L);
verify(trackedEmoteService, times(1)).addEmoteToRuntimeStorage(emote2, guild, 1L);
@@ -78,7 +87,7 @@ public class EmoteTrackingListenerTest {
@Test
public void testExecuteNoEmote() {
when(message.getEmotesBag()).thenReturn(new HashBag<>());
when(message.getEmotes()).thenReturn(new ArrayList<>());
testUnit.execute(message);
verify(trackedEmoteService, times(0)).addEmoteToRuntimeStorage(any(), any(), anyLong());
}
@@ -89,8 +98,4 @@ public class EmoteTrackingListenerTest {
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;
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.emotes.model.database.TrackedEmote;
import dev.sheldan.abstracto.statistic.emotes.service.management.TrackedEmoteManagementService;
import net.dv8tion.jda.api.entities.Emote;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,9 +26,13 @@ public class UpdateTrackedEmoteListenerTest {
@Test
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);
when(trackedEmoteManagementService.loadByEmote(changedEmote)).thenReturn(trackedEmote);
when(trackedEmoteManagementService.loadByEmoteId(emoteId, serverId)).thenReturn(trackedEmote);
String newValue = "AFTER";
testUnit.emoteUpdated(changedEmote, "BEFORE", newValue);
verify(trackedEmoteManagementService, times(1)).changeName(trackedEmote, newValue);

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.statistic.emotes.service;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
import net.dv8tion.jda.api.entities.Emote;
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 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.
* 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 count The amount of usages which should be added
* @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.
@@ -46,21 +47,21 @@ public interface TrackedEmoteRuntimeService {
/**
* Creates a {@link PersistingEmote} from the given parameters.
* @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
* @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.
* @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 external Whether or not the {@link Emote} is external
* @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

View File

@@ -1,5 +1,6 @@
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.TrackedEmoteOverview;
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 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}
* @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 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

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.statistic.emotes.service.management;
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.statistic.emotes.exception.TrackedEmoteNotFoundException;
import dev.sheldan.abstracto.statistic.emotes.model.PersistingEmote;
@@ -33,6 +34,13 @@ public interface TrackedEmoteManagementService {
*/
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}
* @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.HelpInfo;
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.CommandResult;
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 java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -60,8 +62,8 @@ public class Roll extends AbstractConditionableCommand {
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("high").type(Integer.class).templated(true).optional(true).build());
parameters.add(Parameter.builder().name("low").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).validators(Arrays.asList(MinIntegerValueValidator.min(0L))).optional(true).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("roll")

View File

@@ -1,6 +1,6 @@
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.service.management.ConfigManagementService;
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.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.service.MessageCache;
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 lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.Event;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -36,7 +39,7 @@ public class MessageEmbedListener implements MessageReceivedListener {
private MessageEmbedListener self;
@Override
public void execute(Message message) {
public MessageReceivedListenerResult execute(Message message) {
String messageRaw = message.getContentRaw();
List<MessageEmbedLink> links = messageEmbedService.getLinksInMessage(messageRaw);
if(!links.isEmpty()) {
@@ -59,7 +62,12 @@ public class MessageEmbedListener implements MessageReceivedListener {
}
if(StringUtils.isBlank(messageRaw) && !links.isEmpty()) {
message.delete().queue();
return MessageReceivedListenerResult.DELETED;
}
if(!links.isEmpty()) {
return MessageReceivedListenerResult.PROCESSED;
}
return MessageReceivedListenerResult.IGNORED;
}
@Transactional
@@ -73,6 +81,11 @@ public class MessageEmbedListener implements MessageReceivedListener {
});
}
@Override
public boolean shouldConsume(Event event, ExecutionResult result) {
return result.equals(MessageReceivedListenerResult.DELETED);
}
@Override
public FeatureEnum getFeature() {
return UtilityFeature.LINK_EMBEDS;

View File

@@ -1,12 +1,11 @@
package dev.sheldan.abstracto.utility.listener.embed;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.ReactedAddedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
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.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.EmoteService;
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.service.management.MessageEmbedPostManagementService;
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.stereotype.Component;
@@ -23,7 +20,7 @@ import java.util.Optional;
@Component
@Slf4j
public class MessageEmbedRemovalReactionListener implements ReactedAddedListener {
public class MessageEmbedRemovalReactionListener implements AsyncReactionAddedListener {
public static final String REMOVAL_EMOTE = "removeEmbed";
@@ -39,19 +36,16 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
@Autowired
private EmoteService emoteService;
@Override
public void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent event, AUserInAServer userAdding) {
public void executeReactionAdded(CachedMessage message, CachedReactions cachedReaction, ServerUser serverUser) {
Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(REMOVAL_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote();
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) {
if(emoteService.compareCachedEmoteWithAEmote(cachedReaction.getEmote(), aEmote)) {
Optional<EmbeddedMessage> embeddedMessageOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId());
if(embeddedMessageOptional.isPresent()) {
EmbeddedMessage embeddedMessage = embeddedMessageOptional.get();
AUser userReacting = userAdding.getUserReference();
if(embeddedMessage.getEmbeddedUser().getUserReference().getId().equals(userReacting.getId())
|| embeddedMessage.getEmbeddingUser().getUserReference().getId().equals(userReacting.getId())
if(embeddedMessage.getEmbeddedUser().getUserReference().getId().equals(serverUser.getUserId())
|| embeddedMessage.getEmbeddingUser().getUserReference().getId().equals(serverUser.getUserId())
) {
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 ->{
@@ -74,8 +68,4 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
return UtilityFeature.LINK_EMBEDS;
}
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
}

View File

@@ -1,6 +1,6 @@
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.utility.service.RepostServiceBean;
import dev.sheldan.abstracto.utility.service.management.RepostCheckChannelGroupManagement;

View File

@@ -1,6 +1,6 @@
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.utility.service.RepostServiceBean;
import dev.sheldan.abstracto.utility.service.management.RepostCheckChannelGroupManagement;

View File

@@ -1,9 +1,11 @@
package dev.sheldan.abstracto.utility.listener.repost;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.MessageEmbeddedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageEmbeddedListener;
import dev.sheldan.abstracto.core.models.database.AChannel;
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.service.RepostCheckChannelService;
import dev.sheldan.abstracto.utility.service.RepostService;
@@ -19,7 +21,7 @@ import java.util.stream.Collectors;
@Component
@Slf4j
public class RepostEmbedListener implements MessageEmbeddedListener {
public class RepostEmbedListener implements AsyncMessageEmbeddedListener {
@Autowired
private RepostCheckChannelService repostCheckChannelService;
@@ -30,15 +32,22 @@ public class RepostEmbedListener implements MessageEmbeddedListener {
@Autowired
private PostedImageManagement repostManagement;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private BotService botService;
@Override
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())) {
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;
}
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());
repostService.processMessageEmbedsRepostCheck(imageEmbeds, message);
});
@@ -50,9 +59,4 @@ public class RepostEmbedListener implements MessageEmbeddedListener {
return UtilityFeature.REPOST_DETECTION;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

@@ -1,15 +1,16 @@
package dev.sheldan.abstracto.utility.listener.repost;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
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.service.RepostCheckChannelService;
import dev.sheldan.abstracto.utility.service.RepostService;
import lombok.extern.slf4j.Slf4j;
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.stereotype.Component;
@@ -19,7 +20,7 @@ import java.util.stream.Collectors;
@Component
@Slf4j
public class RepostMessageReceivedListener implements MessageReceivedListener {
public class RepostMessageReceivedListener implements AsyncMessageReceivedListener {
@Autowired
private RepostCheckChannelService repostCheckChannelService;
@@ -27,11 +28,15 @@ public class RepostMessageReceivedListener implements MessageReceivedListener {
@Autowired
private RepostService repostService;
@Autowired
private ChannelManagementService channelManagementService;
@Override
public void execute(Message message) {
if(repostCheckChannelService.duplicateCheckEnabledForChannel(message.getTextChannel())) {
public void execute(CachedMessage message) {
AChannel channel = channelManagementService.loadChannel(message.getChannelId());
if(repostCheckChannelService.duplicateCheckEnabledForChannel(channel)) {
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);
}
}
@@ -41,8 +46,4 @@ public class RepostMessageReceivedListener implements MessageReceivedListener {
return UtilityFeature.REPOST_DETECTION;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

@@ -1,12 +1,12 @@
package dev.sheldan.abstracto.utility.listener.starboard;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.listener.ReactedAddedListener;
import dev.sheldan.abstracto.core.listener.ReactedRemovedListener;
import dev.sheldan.abstracto.core.listener.ReactionClearedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionClearedListener;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionRemovedListener;
import dev.sheldan.abstracto.core.models.ServerUser;
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.AUserInAServer;
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.StarboardPostReactorManagementService;
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.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@@ -33,7 +30,7 @@ import java.util.stream.Collectors;
@Component
@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 FIRST_LEVEL_THRESHOLD_KEY = "starLvl1";
@@ -61,34 +58,34 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
@Override
@Transactional
public void executeReactionAdded(CachedMessage message, GuildMessageReactionAddEvent addedReaction, AUserInAServer userAdding) {
if(userAdding.getUserReference().getId().equals(message.getAuthorId())) {
public void executeReactionAdded(CachedMessage message, CachedReactions cachedReaction, ServerUser serverUser) {
if(serverUser.getUserId().equals(message.getAuthor().getAuthorId())) {
return;
}
Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = addedReaction.getReactionEmote();
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) {
log.info("User {} in server {} reacted with star to put a message {} from channel {} on starboard.", userAdding.getUserReference().getId(), userAdding.getServerReference().getId(), message.getMessageId(), message.getChannelId());
Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), userAdding, true);
if(emoteService.compareCachedEmoteWithAEmote(cachedReaction.getEmote(), 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());
Optional<CachedReactions> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), serverUser, 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());
if(reaction != null) {
AUserInAServer author = userInServerManagementService.loadUser(message.getServerId(), message.getAuthorId());
List<AUserInAServer> userExceptAuthor = getUsersExcept(reaction.getUserInServersIds(), author);
AUserInAServer author = userInServerManagementService.loadUser(message.getServerId(), message.getAuthor().getAuthorId());
List<AUserInAServer> userExceptAuthor = getUsersExcept(reaction.getUsers(), author);
Long starMinimum = getFromConfig(FIRST_LEVEL_THRESHOLD_KEY, message.getServerId());
AUserInAServer userAddingReaction = userInServerManagementService.loadUser(serverUser);
if (userExceptAuthor.size() >= starMinimum) {
log.info("Post reached starboard minimum. Message {} in channel {} in server {} will be starred/updated.",
message.getMessageId(), message.getChannelId(), message.getServerId());
if(starboardPostOptional.isPresent()) {
updateStarboardPost(message, userReacting, adding, starboardPostOptional.get(), userExceptAuthor);
updateStarboardPost(message, userAddingReaction, adding, starboardPostOptional.get(), userExceptAuthor);
} else {
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 {
if(starboardPostOptional.isPresent()) {
@@ -124,17 +121,16 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
@Override
@Transactional
public void executeReactionRemoved(CachedMessage message, GuildMessageReactionRemoveEvent removedReaction, AUserInAServer userRemoving) {
if(message.getAuthorId().equals(userRemoving.getUserReference().getId())) {
public void executeReactionRemoved(CachedMessage message, CachedReactions removedReaction, ServerUser userRemoving) {
if(message.getAuthor().getAuthorId().equals(userRemoving.getUserId())) {
return;
}
Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = removedReaction.getReactionEmote();
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) {
if(emoteService.compareCachedEmoteWithAEmote(removedReaction.getEmote(), aEmote)) {
log.info("User {} in server {} removed star reaction from message {} on starboard.",
userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), message.getMessageId());
Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
userRemoving.getUserId(), message.getServerId(), message.getMessageId());
Optional<CachedReactions> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), userRemoving, false);
}
}
@@ -143,9 +139,9 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
return configManagementService.loadConfig(guildId, key).getLongValue();
}
private List<AUserInAServer> getUsersExcept(List<Long> users, AUserInAServer author) {
return users.stream().filter(user -> !user.equals(author.getUserInServerId())).map(aLong -> {
Optional<AUserInAServer> aUserInAServer = userInServerManagementService.loadUserConditional(aLong);
private List<AUserInAServer> getUsersExcept(List<ServerUser> users, AUserInAServer author) {
return users.stream().filter(user -> !(user.getServerId().equals(author.getServerReference().getId()) && user.getUserId().equals(author.getUserReference().getId()))).map(serverUser -> {
Optional<AUserInAServer> aUserInAServer = userInServerManagementService.loadUserOptional(serverUser.getServerId(), serverUser.getUserId());
return aUserInAServer.orElse(null);
}).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;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.ListenerPriority;
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.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.database.StarboardPost;
@@ -17,18 +14,18 @@ import java.util.Optional;
@Component
@Slf4j
public class StarboardPostDeletedListener implements MessageDeletedListener {
public class StarboardPostDeletedListener implements AsyncMessageDeletedListener {
@Autowired
private StarboardPostManagementService starboardPostManagementService;
@Override
public void execute(CachedMessage messageBefore, AServerAChannelAUser authorUser, GuildChannelMember authorMember) {
public void execute(CachedMessage messageBefore) {
Optional<StarboardPost> byStarboardPostId = starboardPostManagementService.findByStarboardPostId(messageBefore.getMessageId());
if(byStarboardPostId.isPresent()) {
StarboardPost post = byStarboardPostId.get();
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);
}
}
@@ -38,8 +35,4 @@ public class StarboardPostDeletedListener implements MessageDeletedListener {
return UtilityFeature.STARBOARD;
}
@Override
public Integer getPriority() {
return ListenerPriority.HIGH;
}
}

View File

@@ -111,7 +111,7 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
@Override
@Transactional
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()) {
return buildTemplateParameter(embeddingMessage, cachedMessage).thenCompose(messageEmbeddedModel ->
self.sendEmbeddingMessage(cachedMessage, target, userEmbeddingUserInServerId, messageEmbeddedModel)
@@ -145,7 +145,7 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
}
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)
);
}

View File

@@ -1,6 +1,10 @@
package dev.sheldan.abstracto.utility.service;
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.AUserInAServer;
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";
@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();
}
@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
public Optional<PostedImage> getRepostFor(Message message, MessageEmbed messageEmbed, Integer embedIndex) {
if(messageEmbed.getThumbnail() == null && messageEmbed.getImage() == null) {
@@ -100,38 +125,52 @@ public class RepostServiceBean implements RepostService {
} else if (messageEmbed.getImage() != null) {
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) {
String fileHash = calculateHashForPost(fileUrl, message.getGuild().getIdLong());
AServer aServer = serverManagementService.loadServer(message.getGuild().getIdLong());
private Optional<PostedImage> checkForDuplicates(ServerChannelMessageUser serverChannelMessageUser, Integer index, String fileUrl) {
String fileHash = calculateHashForPost(fileUrl, serverChannelMessageUser.getServerId());
AServer aServer = serverManagementService.loadServer(serverChannelMessageUser.getServerId());
Optional<PostedImage> potentialRepost = postedImageManagement.getPostWithHash(fileHash, aServer);
if(potentialRepost.isPresent()) {
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 {
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(message.getMember());
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(serverChannelMessageUser.getServerId(), serverChannelMessageUser.getUserId());
AServerAChannelAUser cause = AServerAChannelAUser
.builder()
.aUserInAServer(aUserInAServer)
.channel(channelManagementService.loadChannel(message.getTextChannel().getIdLong()))
.channel(channelManagementService.loadChannel(serverChannelMessageUser.getChannelId()))
.guild(aServer)
.user(aUserInAServer.getUserReference())
.build();
postedImageManagement.createPost(cause, message, fileHash, index);
postedImageManagement.createPost(cause, serverChannelMessageUser.getMessageId(), fileHash, index);
return Optional.empty();
}
}
@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();
}
@Override
public Optional<PostedImage> getRepostFor(Message message, Message.Attachment attachment, Integer index) {
return checkForDuplicates(message, index, attachment.getProxyUrl());
public Optional<PostedImage> getRepostFor(CachedMessage message, CachedAttachment attachment, Integer index) {
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
@@ -159,31 +198,38 @@ public class RepostServiceBean implements RepostService {
}
@Override
public void processMessageAttachmentRepostCheck(Message message) {
public void processMessageAttachmentRepostCheck(CachedMessage message) {
boolean canThereBeMultipleReposts = message.getAttachments().size() > 1;
for (int imageIndex = 0; imageIndex < message.getAttachments().size(); imageIndex++) {
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);
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) {
log.info("Detected repost in message embed {} of message {} in channel {} in server {}.", index, message.getIdLong(), message.getTextChannel().getIdLong(), message.getGuild().getIdLong());
CompletableFuture<Void> markerFuture = messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, message.getGuild().getIdLong(), message);
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, messageUser.getMessageId(), messageUser.getChannelId(), messageUser.getServerId());
CompletableFuture<Void> markerFuture = messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, messageUser.getServerId(), messageUser.getChannelId(), messageUser.getMessageId());
CompletableFuture<Void> counterFuture;
if (moreRepostsPossible) {
counterFuture = messageService.addDefaultReactionToMessageAsync(NUMBER_EMOJI.get(index), message);
counterFuture = messageService.addDefaultReactionToMessageAsync(NUMBER_EMOJI.get(index), messageUser.getServerId(), messageUser.getChannelId(), messageUser.getMessageId());
} else {
counterFuture = CompletableFuture.completedFuture(null);
}
Long messageId = originalPost.getPostId().getMessageId();
Integer position = originalPost.getPostId().getPosition();
Long serverId = message.getGuild().getIdLong();
Long userId = message.getAuthor().getIdLong();
Long serverId = messageUser.getServerId();
Long userId = messageUser.getUserId();
CompletableFuture.allOf(markerFuture, counterFuture).thenAccept(unused ->
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
public void processMessageEmbedsRepostCheck(List<MessageEmbed> embeds, Message message) {
boolean canThereBeMultipleReposts = embeds.size() > 1 || !message.getAttachments().isEmpty();
@@ -228,8 +282,27 @@ public class RepostServiceBean implements RepostService {
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) {
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
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);
Message message1 = completableFutures.get(0).join();
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());
}
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);
});
}
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<Guild> guild = botService.getGuildByIdOptional(message.getServerId());
// TODO use model objects instead of building entity models
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();
String starLevelEmote = getAppropriateEmote(message.getServerId(), starCount);
return StarboardPostModel

View File

@@ -44,7 +44,7 @@ public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostMa
}
AChannel embeddingChannel = channelManagementService.loadChannel(messageContainingEmbed.getChannel().getIdLong());
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
.builder()
.embeddedMessageId(embeddedMessage.getMessageId())
@@ -58,8 +58,8 @@ public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostMa
.build();
log.info("Saving embedded post: message {} by user {} in channel {} in server {} embedded message {} by user {} in channel {} in server {}.",
messageContainingEmbed.getIdLong(), embeddingUser.getUserReference().getId(), embeddingChannel.getId(), embeddingUser.getServerReference().getId(),
embeddedMessage.getMessageId(), embeddedMessage.getAuthorId(), embeddedMessage.getChannelId(), embeddedMessage.getServerId());
messageContainingEmbed.getIdLong(), messageContainingEmbed.getAuthor().getIdLong(), embeddingChannel.getId(), messageContainingEmbed.getChannel().getIdLong(),
embeddedMessage.getMessageId(), embeddedMessage.getAuthor().getAuthorId(), embeddedMessage.getChannelId(), embeddedMessage.getServerId());
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.repository.PostedImageRepository;
import dev.sheldan.abstracto.utility.service.RepostServiceBean;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -25,11 +24,11 @@ public class PostedImageManagementBean implements PostedImageManagement {
private RepostCheckChannelGroupManagement checkChannelBean;
@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
.builder()
.imageHash(hash)
.postId(new PostIdentifier(source.getIdLong(), index))
.postId(new PostIdentifier(messageId, index))
.poster(creation.getAUserInAServer())
.server(creation.getGuild())
.postedChannel(creation.getChannel())

View File

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

View File

@@ -1,6 +1,9 @@
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.service.BotService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.utility.service.RepostCheckChannelService;
import dev.sheldan.abstracto.utility.service.RepostService;
import dev.sheldan.abstracto.utility.service.management.PostedImageManagement;
@@ -33,6 +36,12 @@ public class RepostEmbedListenerTest {
@Mock
private PostedImageManagement repostManagement;
@Mock
private ChannelManagementService channelManagementService;
@Mock
private BotService botService;
@Mock
private GuildMessageEmbedEventModel model;
@@ -42,6 +51,9 @@ public class RepostEmbedListenerTest {
@Mock
private Message message;
@Mock
private AChannel channel;
@Captor
private ArgumentCaptor<List<MessageEmbed>> embedListsParameterCaptor;
@@ -51,8 +63,7 @@ public class RepostEmbedListenerTest {
@Test
public void testExecuteCheckDisabled() {
when(model.getChannel()).thenReturn(textChannel);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(textChannel)).thenReturn(false);
when(model.getChannelId()).thenReturn(CHANNEL_ID);
testUnit.execute(model);
verify(repostManagement, times(0)).messageEmbedsHaveBeenCovered(anyLong());
}
@@ -61,11 +72,8 @@ public class RepostEmbedListenerTest {
public void testExecuteEmbedsHaveBeenCovered() {
channelSetup();
setupMessageHasBeenCovered(true);
Guild guild = Mockito.mock(Guild.class);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(textChannel.getGuild()).thenReturn(guild);
testUnit.execute(model);
verify(repostService, times(0)).processMessageEmbedsRepostCheck(any(), any());
verify(repostService, times(0)).processMessageEmbedsRepostCheck(anyList(), any(Message.class));
}
@Test
@@ -75,7 +83,7 @@ public class RepostEmbedListenerTest {
RestAction messageRestAction = Mockito.mock(RestAction.class);
when(textChannel.retrieveMessageById(MESSAGE_ID)).thenReturn(messageRestAction);
testUnit.execute(model);
verify(repostService, times(0)).processMessageEmbedsRepostCheck(any(), any());
verify(repostService, times(0)).processMessageEmbedsRepostCheck(anyList(), any(Message.class));
}
@Test
@@ -132,9 +140,11 @@ public class RepostEmbedListenerTest {
}
private void channelSetup() {
when(model.getChannel()).thenReturn(textChannel);
when(textChannel.getIdLong()).thenReturn(CHANNEL_ID);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(textChannel)).thenReturn(true);
when(model.getChannelId()).thenReturn(CHANNEL_ID);
when(model.getServerId()).thenReturn(SERVER_ID);
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;
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.RepostService;
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.Test;
import org.junit.runner.RunWith;
@@ -26,17 +27,22 @@ public class RepostMessageReceivedListenerTest {
@Mock
private RepostCheckChannelService repostCheckChannelService;
@Mock
private ChannelManagementService channelManagementService;
@Mock
private RepostService repostService;
@Mock
private Message message;
private CachedMessage message;
@Mock
private TextChannel textChannel;
private AChannel channel;
@Captor
private ArgumentCaptor<List<MessageEmbed>> embedListCaptor;
private ArgumentCaptor<List<CachedEmbed>> embedListCaptor;
private static final Long CHANNEL_ID = 4L;
@Test
public void testExecuteCheckDisabled() {
@@ -57,7 +63,7 @@ public class RepostMessageReceivedListenerTest {
@Test
public void testExecuteOnlyMessageOneImageAttachment() {
setupRepostCheckEnabled(true);
MessageEmbed imageEmbed = Mockito.mock(MessageEmbed.class);
CachedEmbed imageEmbed = Mockito.mock(CachedEmbed.class);
when(imageEmbed.getType()).thenReturn(EmbedType.IMAGE);
when(message.getEmbeds()).thenReturn(Arrays.asList(imageEmbed));
testUnit.execute(message);
@@ -67,9 +73,9 @@ public class RepostMessageReceivedListenerTest {
@Test
public void testExecuteOnlyMessageTwoEmbedsOneImageAttachment() {
setupRepostCheckEnabled(true);
MessageEmbed imageEmbed = Mockito.mock(MessageEmbed.class);
CachedEmbed imageEmbed = Mockito.mock(CachedEmbed.class);
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(message.getEmbeds()).thenReturn(Arrays.asList(imageEmbed, nonImageEmbed));
testUnit.execute(message);
@@ -77,14 +83,15 @@ public class RepostMessageReceivedListenerTest {
}
private void setupRepostCheckEnabled(boolean b) {
when(message.getTextChannel()).thenReturn(textChannel);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(textChannel)).thenReturn(b);
when(message.getChannelId()).thenReturn(CHANNEL_ID);
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)).processMessageEmbedsRepostCheck(embedListCaptor.capture(), eq(message));
List<MessageEmbed> processedEmbeds = embedListCaptor.getValue();
List<CachedEmbed> processedEmbeds = embedListCaptor.getValue();
Assert.assertEquals(1, processedEmbeds.size());
Assert.assertEquals(imageEmbed, processedEmbeds.get(0));
}

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
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.database.AUserInAServer;
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 SERVER_ID = 8L;
private static final Long CHANNEL_ID = 10L;
private static final Long USER_ID = 9L;
@Mock
@@ -145,11 +147,10 @@ public class MessageEmbedServiceBeanTest {
public void testEmbedSingularLink() {
List<MessageEmbedLink> linksToEmbed = new ArrayList<>();
Long channelId = 6L;
Long serverId = 4L;
Long firstMessageId = 6L;
linksToEmbed.add(MessageEmbedLink.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build());
CachedMessage firstCachedMessage = CachedMessage.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build();
when(messageCache.getMessageFromCache(serverId,channelId, firstMessageId)).thenReturn(CompletableFuture.completedFuture(firstCachedMessage));
linksToEmbed.add(MessageEmbedLink.builder().serverId(SERVER_ID).channelId(channelId).messageId(firstMessageId).build());
CachedMessage firstCachedMessage = CachedMessage.builder().serverId(SERVER_ID).channelId(channelId).messageId(firstMessageId).build();
when(messageCache.getMessageFromCache(SERVER_ID,channelId, firstMessageId)).thenReturn(CompletableFuture.completedFuture(firstCachedMessage));
Long embeddingUserId = 5L;
testUnit.embedLinks(linksToEmbed, textChannel, embeddingUserId, embeddingMessage);
verify( self, times(1)).embedLink(eq(firstCachedMessage), eq(textChannel), eq(embeddingUserId) , eq(embeddingMessage));
@@ -158,16 +159,16 @@ public class MessageEmbedServiceBeanTest {
@Test
public void testEmbedMultipleLinks() {
List<MessageEmbedLink> linksToEmbed = new ArrayList<>();
Long channelId = 6L;
Long serverId = 4L;
Long firstMessageId = 6L;
Long secondMessageId = 7L;
linksToEmbed.add(MessageEmbedLink.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build());
linksToEmbed.add(MessageEmbedLink.builder().serverId(serverId).channelId(channelId).messageId(secondMessageId).build());
CachedMessage firstCachedMessage = CachedMessage.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build();
CachedMessage secondCacheMessage = CachedMessage.builder().serverId(serverId).channelId(channelId).messageId(secondMessageId).build();
when(messageCache.getMessageFromCache(serverId,channelId, firstMessageId)).thenReturn(CompletableFuture.completedFuture(firstCachedMessage));
when(messageCache.getMessageFromCache(serverId,channelId, secondMessageId)).thenReturn(CompletableFuture.completedFuture(secondCacheMessage));
MessageEmbedLink messageEmbedLink = mockMessageEmbedLink(firstMessageId);
linksToEmbed.add(messageEmbedLink);
MessageEmbedLink secondMessageEmbedLink = mockMessageEmbedLink(secondMessageId);
linksToEmbed.add(secondMessageEmbedLink);
CachedMessage firstCachedMessage = mockCachedMessage(firstMessageId);
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;
testUnit.embedLinks(linksToEmbed, textChannel, embeddingUserId, 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();
Assert.assertEquals(2, cachedMessages.size());
CachedMessage firstEmbeddedMessage = cachedMessages.get(0);
Assert.assertEquals(serverId, firstEmbeddedMessage.getServerId());
Assert.assertEquals(channelId, firstEmbeddedMessage.getChannelId());
Assert.assertEquals(SERVER_ID, firstEmbeddedMessage.getServerId());
Assert.assertEquals(CHANNEL_ID, firstEmbeddedMessage.getChannelId());
Assert.assertEquals(firstMessageId, firstEmbeddedMessage.getMessageId());
CachedMessage secondEmbeddedMessage = cachedMessages.get(1);
Assert.assertEquals(serverId, secondEmbeddedMessage.getServerId());
Assert.assertEquals(channelId, secondEmbeddedMessage.getChannelId());
Assert.assertEquals(SERVER_ID, secondEmbeddedMessage.getServerId());
Assert.assertEquals(CHANNEL_ID, secondEmbeddedMessage.getChannelId());
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
public void testLoadingEmbeddingModel() {
CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
when(cachedMessage.getServerId()).thenReturn(SERVER_ID);
when(cachedMessage.getAuthorId()).thenReturn(USER_ID);
when(userInServerManagementService.loadUserConditional(EMBEDDING_USER_IN_SERVER_ID)).thenReturn(Optional.of(embeddingUser));
CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
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));
MessageEmbeddedModel model = Mockito.mock(MessageEmbeddedModel.class);
when(self.loadMessageEmbedModel(embeddingMessage, cachedMessage, embeddingMember)).thenReturn(model);
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
public void testNotFoundUserEmbeddingLink() {
Long channelId = 6L;
Long serverId = 4L;
Long firstMessageId = 6L;
CachedMessage cachedMessage = CachedMessage.builder().serverId(serverId).channelId(channelId).messageId(firstMessageId).build();
CachedMessage cachedMessage = mockCachedMessage(firstMessageId);
Long userEmbeddingUserInServerId = 5L;
when(userInServerManagementService.loadUserConditional(userEmbeddingUserInServerId)).thenReturn(Optional.empty());
when(userInServerManagementService.loadUserOptional(userEmbeddingUserInServerId)).thenReturn(Optional.empty());
testUnit.embedLink(cachedMessage, textChannel, userEmbeddingUserInServerId, embeddingMessage);
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.utility.service;
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.AServer;
import dev.sheldan.abstracto.core.models.database.AUser;
@@ -107,16 +108,10 @@ public class RepostServiceBeanTest {
private Repost repost;
@Mock
private Message message;
private CachedMessage message;
@Mock
private TextChannel textChannel;
@Mock
private Member member;
@Mock
private User jdaUser;
private CachedAuthor author;
private static final Long SERVER_ID = 4L;
private static final Long CHANNEL_ID = 8L;
@@ -213,35 +208,38 @@ public class RepostServiceBeanTest {
public void testProcessMessageAttachmentRepostCheckNoAttachment() {
when(message.getAttachments()).thenReturn(new ArrayList<>());
testUnit.processMessageAttachmentRepostCheck(message);
verify(message, times(0)).getTextChannel();
verify(message, times(0)).getChannelId();
}
@Test
public void testProcessMessageAttachmentRepostCheckOneAttachmentNotExistingPost() {
generalSetupForRepostTest();
when(message.getMember()).thenReturn(member);
Message.Attachment attachment = Mockito.mock(Message.Attachment.class);
when(message.getServerId()).thenReturn(SERVER_ID);
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(attachment.getProxyUrl()).thenReturn(URL);
setupSingleRepost();
testUnit.processMessageAttachmentRepostCheck(message);
verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(message), eq(HASH), eq(0));
verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message);
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, CHANNEL_ID, MESSAGE_ID);
}
@Test
public void testProcessMessageAttachmentRepostCheckOneAttachmentIsRepost() {
generalSetupForRepostTest();
setupForRepostCreation();
Message.Attachment attachment = Mockito.mock(Message.Attachment.class);
CachedAttachment attachment = Mockito.mock(CachedAttachment.class);
when(message.getAttachments()).thenReturn(Arrays.asList(attachment));
when(attachment.getProxyUrl()).thenReturn(URL);
setupSingleHash(postedImage);
Long originalPostMessageId = MESSAGE_ID + 1;
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);
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);
}
@@ -249,9 +247,10 @@ public class RepostServiceBeanTest {
public void testProcessMessageAttachmentRepostCheckTwoAttachmentsOneIsRepost() {
generalSetupForRepostTest();
setupForRepostCreation();
when(message.getMember()).thenReturn(member);
Message.Attachment attachment = Mockito.mock(Message.Attachment.class);
Message.Attachment attachment2 = Mockito.mock(Message.Attachment.class);
when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getAuthor().getAuthorId()).thenReturn(USER_ID);
CachedAttachment attachment = Mockito.mock(CachedAttachment.class);
CachedAttachment attachment2 = Mockito.mock(CachedAttachment.class);
when(message.getAttachments()).thenReturn(Arrays.asList(attachment, attachment2));
when(attachment.getProxyUrl()).thenReturn(URL);
setupSingleRepost();
@@ -262,30 +261,28 @@ public class RepostServiceBeanTest {
when(postedImageManagement.getPostWithHash(secondAttachmentHash, server)).thenReturn(Optional.of(postedImage));
Long originalPostMessageId = MESSAGE_ID + 1;
when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION));
when(messageService.addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message)).thenReturn(CompletableFuture.completedFuture(null));
when(messageService.addDefaultReactionToMessageAsync(anyString(), eq(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(SERVER_ID), eq(CHANNEL_ID), eq(MESSAGE_ID))).thenReturn(CompletableFuture.completedFuture(null));
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);
}
private void setupForRepostCreation() {
when(message.getIdLong()).thenReturn(MESSAGE_ID);
when(message.getAuthor()).thenReturn(jdaUser);
when(jdaUser.getIdLong()).thenReturn(USER_ID);
when(message.getMessageId()).thenReturn(MESSAGE_ID);
when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getAuthor()).thenReturn(author);
when(author.getAuthorId()).thenReturn(USER_ID);
when(message.getChannelId()).thenReturn(CHANNEL_ID);
}
private void generalSetupForRepostTest() {
when(message.getTextChannel()).thenReturn(textChannel);
when(textChannel.getIdLong()).thenReturn(CHANNEL_ID);
when(message.getGuild()).thenReturn(guild);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(userInServerManagementService.loadUser(SERVER_ID, USER_ID)).thenReturn(userInAServer);
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
}
private void setupSingleRepost() {
setupSingleHash(null);
when(userInServerManagementService.loadUser(member)).thenReturn(userInAServer);
when(userInAServer.getUserReference()).thenReturn(user);
when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(channel);
}
@@ -299,56 +296,62 @@ public class RepostServiceBeanTest {
@Test
public void testProcessMessageEmbedsRepostCheckWithNotRepostedThumbnailNoAttachments() {
generalSetupForRepostTest();
MessageEmbed firstEmbed = Mockito.mock(MessageEmbed.class);
MessageEmbed.Thumbnail thumbnail = Mockito.mock(MessageEmbed.Thumbnail.class);
CachedEmbed firstEmbed = Mockito.mock(CachedEmbed.class);
CachedThumbnail thumbnail = Mockito.mock(CachedThumbnail.class);
when(thumbnail.getProxyUrl()).thenReturn(URL);
when(firstEmbed.getThumbnail()).thenReturn(thumbnail);
List<MessageEmbed> messageEmbeds = Arrays.asList(firstEmbed);
when(message.getMember()).thenReturn(member);
when(firstEmbed.getCachedThumbnail()).thenReturn(thumbnail);
List<CachedEmbed> messageEmbeds = Arrays.asList(firstEmbed);
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<>());
setupSingleRepost();
testUnit.processMessageEmbedsRepostCheck(messageEmbeds, message);
verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(message), eq(HASH), eq(EMBEDDED_LINK_POSITION_START_INDEX));
verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message);
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, CHANNEL_ID, MESSAGE_ID);
}
@Test
public void testProcessMessageEmbedsRepostCheckWithNotRepostedEmbedImageNoAttachments() {
generalSetupForRepostTest();
MessageEmbed firstEmbed = Mockito.mock(MessageEmbed.class);
MessageEmbed.ImageInfo thumbnail = Mockito.mock(MessageEmbed.ImageInfo.class);
when(thumbnail.getProxyUrl()).thenReturn(URL);
when(firstEmbed.getImage()).thenReturn(thumbnail);
List<MessageEmbed> messageEmbeds = Arrays.asList(firstEmbed);
when(message.getMember()).thenReturn(member);
CachedEmbed firstEmbed = Mockito.mock(CachedEmbed.class);
CachedImageInfo image = Mockito.mock(CachedImageInfo.class);
when(image.getProxyUrl()).thenReturn(URL);
when(firstEmbed.getCachedImageInfo()).thenReturn(image);
List<CachedEmbed> messageEmbeds = Arrays.asList(firstEmbed);
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<>());
setupSingleRepost();
testUnit.processMessageEmbedsRepostCheck(messageEmbeds, message);
verify(postedImageManagement, times(1)).createPost(any(AServerAChannelAUser.class), eq(message), eq(HASH), eq(EMBEDDED_LINK_POSITION_START_INDEX));
verify(messageService, times(0)).addReactionToMessageWithFuture(REPOST_MARKER_EMOTE_KEY, SERVER_ID, message);
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, CHANNEL_ID, MESSAGE_ID);
}
@Test
public void testProcessMessageEmbedsRepostCheckWithRepostedThumbnailNoAttachments() {
generalSetupForRepostTest();
setupForRepostCreation();
MessageEmbed firstEmbed = Mockito.mock(MessageEmbed.class);
MessageEmbed.Thumbnail thumbnail = Mockito.mock(MessageEmbed.Thumbnail.class);
CachedEmbed firstEmbed = Mockito.mock(CachedEmbed.class);
CachedThumbnail thumbnail = Mockito.mock(CachedThumbnail.class);
when(thumbnail.getProxyUrl()).thenReturn(URL);
when(firstEmbed.getThumbnail()).thenReturn(thumbnail);
List<MessageEmbed> messageEmbeds = Arrays.asList(firstEmbed);
when(firstEmbed.getCachedThumbnail()).thenReturn(thumbnail);
List<CachedEmbed> messageEmbeds = Arrays.asList(firstEmbed);
when(message.getAttachments()).thenReturn(new ArrayList<>());
setupSingleHash(postedImage);
Long originalPostMessageId = MESSAGE_ID + 1;
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);
verify(self, times(1)).persistRepost(originalPostMessageId, POSITION, SERVER_ID, USER_ID);
}
@Test
public void testIsRepostEmptyEmbedMessage() {
MessageEmbed messageEmbed = Mockito.mock(MessageEmbed.class);
CachedEmbed messageEmbed = Mockito.mock(CachedEmbed.class);
Optional<PostedImage> emptyOptional = testUnit.getRepostFor(message, messageEmbed, POSITION);
Assert.assertFalse(emptyOptional.isPresent());
}
@@ -364,7 +367,7 @@ public class RepostServiceBeanTest {
}
private void executeGetRepostForWithMessageId(Long originalPostMessageId, boolean shouldBePresent) {
MessageEmbed messageEmbed = setupSimpleRepostCheck(originalPostMessageId);
CachedEmbed messageEmbed = setupSimpleRepostCheck(originalPostMessageId);
Optional<PostedImage> optional = testUnit.getRepostFor(message, messageEmbed, POSITION);
Assert.assertEquals(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();
setupForRepostCreation();
setupSingleHash(postedImage);
when(postedImage.getPostId()).thenReturn(new PostIdentifier(originalPostMessageId, POSITION));
MessageEmbed messageEmbed = Mockito.mock(MessageEmbed.class);
MessageEmbed.Thumbnail thumbnail = Mockito.mock(MessageEmbed.Thumbnail.class);
CachedEmbed messageEmbed = Mockito.mock(CachedEmbed.class);
CachedThumbnail thumbnail = Mockito.mock(CachedThumbnail.class);
when(thumbnail.getProxyUrl()).thenReturn(URL);
when(messageEmbed.getThumbnail()).thenReturn(thumbnail);
when(messageEmbed.getCachedThumbnail()).thenReturn(thumbnail);
return messageEmbed;
}
@Test
public void testIsRepostWithRepost() {
MessageEmbed messageEmbed = setupSimpleRepostCheck(MESSAGE_ID + 1);
CachedEmbed messageEmbed = setupSimpleRepostCheck(MESSAGE_ID + 1);
Assert.assertTrue(testUnit.isRepost(message, messageEmbed, POSITION));
}
@Test
public void testIsRepostWithSameMessage() {
MessageEmbed messageEmbed = setupSimpleRepostCheck(MESSAGE_ID);
CachedEmbed messageEmbed = setupSimpleRepostCheck(MESSAGE_ID);
Assert.assertFalse(testUnit.isRepost(message, messageEmbed, POSITION));
}
@@ -402,8 +405,11 @@ public class RepostServiceBeanTest {
setupSingleRepost();
setupSingleHash(postedImage);
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(message.getServerId()).thenReturn(SERVER_ID);
when(author.getAuthorId()).thenReturn(USER_ID);
when(message.getAuthor()).thenReturn(author);
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.models.AServerAChannelMessage;
import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.*;
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.templating.model.MessageToSend;
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.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.models.database.StarboardPostReaction;
@@ -102,10 +102,17 @@ public class StarboardServiceBeanTest {
@Mock
private MessageToSend messageToSend;
@Mock
private AServer server;
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 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
private ArgumentCaptor<AUserInAServer> userInAServerArgumentCaptor;
@@ -115,31 +122,33 @@ public class StarboardServiceBeanTest {
@Test
public void testCreateStarboardPost() {
AServer server = MockUtils.getServer();
List<AUserInAServer > userExceptAuthor = new ArrayList<>();
userExceptAuthor.add(MockUtils.getUserObject(2L, server));
userExceptAuthor.add(MockUtils.getUserObject(10L, server));
AUserInAServer userReacting = MockUtils.getUserObject(4L, server);
AUserInAServer starredUser = MockUtils.getUserObject(5L, server);
Long channelId = 10L;
Long starredUserId = starredUser.getUserReference().getId();
CachedMessage message = CachedMessage
.builder()
.authorId(starredUserId)
.serverId(server.getId())
.channelId(channelId)
.build();
List<AUserInAServer> userExceptAuthor = new ArrayList<>();
AUserInAServer firstUserExceptAuthor = Mockito.mock(AUserInAServer.class);
userExceptAuthor.add(firstUserExceptAuthor);
AUserInAServer secondUserExceptAuthor = Mockito.mock(AUserInAServer.class);
userExceptAuthor.add(secondUserExceptAuthor);
AUserInAServer userReacting = Mockito.mock(AUserInAServer.class);
AUserInAServer starredUser = Mockito.mock(AUserInAServer.class);
when(starredUser.getUserInServerId()).thenReturn(STARRED_SERVER_USER_ID);
CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
when(cachedAuthor.getAuthorId()).thenReturn(STARRED_USER_ID);
CachedMessage message = Mockito.mock(CachedMessage.class);
when(message.getAuthor()).thenReturn(cachedAuthor);
when(message.getServerId()).thenReturn(SERVER_ID);
when(message.getChannelId()).thenReturn(CHANNEL_ID);
Member authorMember = Mockito.mock(Member.class);
when(botService.getMemberInServerAsync(message.getServerId(), message.getAuthorId())).thenReturn(CompletableFuture.completedFuture(authorMember));
when(botService.getTextChannelFromServerOptional(server.getId(), channelId)).thenReturn(Optional.of(mockedTextChannel));
when(botService.getGuildByIdOptional(server.getId())).thenReturn(Optional.of(guild));
ADefaultConfig config = ADefaultConfig.builder().longValue(3L).build();
when(botService.getMemberInServerAsync(SERVER_ID, STARRED_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
when(botService.getTextChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.of(mockedTextChannel));
when(botService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild));
ADefaultConfig config = Mockito.mock(ADefaultConfig.class);
when(config.getLongValue()).thenReturn(3L);
when(defaultConfigManagementService.getDefaultConfig(StarboardServiceBean.STAR_LEVELS_CONFIG_KEY)).thenReturn(config);
when(configService.getLongValue("starLvl3", server.getId())).thenReturn(3L);
when(configService.getLongValue("starLvl2", server.getId())).thenReturn(2L);
when(emoteService.getUsableEmoteOrDefault(server.getId(), "star2")).thenReturn("b");
when(self.sendStarboardPostAndStore(eq(message), eq(starredUserId), anyList(), any())).thenReturn(CompletableFuture.completedFuture(null));
testUnit.createStarboardPost(message, userExceptAuthor, userReacting, starredUser).join();
when(configService.getLongValue("starLvl3", SERVER_ID)).thenReturn(3L);
when(configService.getLongValue("starLvl2", SERVER_ID)).thenReturn(2L);
when(emoteService.getUsableEmoteOrDefault(SERVER_ID, "star2")).thenReturn("b");
when(self.sendStarboardPostAndStore(eq(message), eq(STARRED_SERVER_USER_ID), anyList(), any())).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<Void> createPostFuture = testUnit.createStarboardPost(message, userExceptAuthor, userReacting, starredUser);
Assert.assertTrue(createPostFuture.isDone());
}
@Test
@@ -159,116 +168,116 @@ public class StarboardServiceBeanTest {
}
@Test
public void testPersistPost() {
AServer server = MockUtils.getServer();
AUserInAServer userReacting = MockUtils.getUserObject(4L, server);
AUserInAServer starredUser = MockUtils.getUserObject(5L, server);
Long channelId = 10L;
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());
public void testPersistPostWithTwoReactors() {
AUserInAServer userReacting = Mockito.mock(AUserInAServer.class);
AUserInAServer starredUser = Mockito.mock(AUserInAServer.class);
CachedMessage message = Mockito.mock(CachedMessage.class);
List<Long> userExceptAuthorIds = Arrays.asList(FIRST_USER_IN_SERVER_ID, SECOND_USER_IN_SERVER_ID);
List<CompletableFuture<Message>> futures = Arrays.asList(CompletableFuture.completedFuture(sendPost));
when(userInServerManagementService.loadUserConditional(starredUser.getUserInServerId())).thenReturn(Optional.of(starredUser));
when(userInServerManagementService.loadUserConditional(userReacting.getUserInServerId())).thenReturn(Optional.of(userReacting));
AChannel channel = MockUtils.getTextChannel(server, channelId);
when(channelManagementService.loadChannel(channelId)).thenReturn(channel);
StarboardPost post = StarboardPost.builder().build();
when(userInServerManagementService.loadUserOptional(STARRED_SERVER_USER_ID)).thenReturn(Optional.of(starredUser));
when(userInServerManagementService.loadUserOptional(FIRST_USER_IN_SERVER_ID)).thenReturn(Optional.of(userReacting));
when(userReacting.getUserInServerId()).thenReturn(FIRST_USER_IN_SERVER_ID);
AChannel channel = Mockito.mock(AChannel.class);
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);
AUserInAServer secondStarrerUserObj = MockUtils.getUserObject(secondStarrerUserId, server);
when(userInServerManagementService.loadUserConditional(secondStarrerUserId)).thenReturn(Optional.of(secondStarrerUserObj));
when(userInServerManagementService.loadUserConditional(userReacting.getUserInServerId())).thenReturn(Optional.of(userReacting));
testUnit.persistPost(message, userExceptAuthorIds, futures, channelId, starredUser.getUserInServerId());
AUserInAServer secondStarrerUserObj = Mockito.mock(AUserInAServer.class);
when(userInServerManagementService.loadUserOptional(SECOND_USER_IN_SERVER_ID)).thenReturn(Optional.of(secondStarrerUserObj));
when(secondStarrerUserObj.getUserInServerId()).thenReturn(SECOND_USER_IN_SERVER_ID);
testUnit.persistPost(message, userExceptAuthorIds, futures, CHANNEL_ID, STARRED_SERVER_USER_ID);
verify(starboardPostReactorManagementService, times(2)).addReactor(eq(post), userInAServerArgumentCaptor.capture());
List<AUserInAServer> addedReactors = userInAServerArgumentCaptor.getAllValues();
Assert.assertEquals(secondStarrerUserId, addedReactors.get(0).getUserInServerId());
Assert.assertEquals(userReacting.getUserInServerId(), addedReactors.get(1).getUserInServerId());
Assert.assertEquals(FIRST_USER_IN_SERVER_ID, addedReactors.get(0).getUserInServerId());
Assert.assertEquals(SECOND_USER_IN_SERVER_ID, addedReactors.get(1).getUserInServerId());
Assert.assertEquals(2, addedReactors.size());
}
@Test
public void testUpdateStarboardPost() {
AServer server = MockUtils.getServer();
Long postMessageId = 25L;
Long newPostId= 37L;
Long newPostId = 37L;
Long oldPostId = 36L;
AUserInAServer starredUser = MockUtils.getUserObject(5L, server);
Long channelId = 10L;
AChannel sourceChannel = Mockito.mock(AChannel.class);
when(sourceChannel.getServer()).thenReturn(server);
CachedMessage message = CachedMessage
.builder()
.authorId(starredUser.getUserReference().getId())
.serverId(server.getId())
.channelId(channelId)
.build();
CachedMessage message = Mockito.mock(CachedMessage.class);
when(message.getChannelId()).thenReturn(CHANNEL_ID);
when(message.getServerId()).thenReturn(SERVER_ID);
CachedAuthor author = Mockito.mock(CachedAuthor.class);
when(author.getAuthorId()).thenReturn(STARRED_USER_ID);
when(message.getAuthor()).thenReturn(author);
Long starboardPostId = 47L;
StarboardPost post = StarboardPost.builder().postMessageId(postMessageId).starboardMessageId(oldPostId).sourceChanel(sourceChannel).id(starboardPostId).build();
MessageToSend postMessage = MessageToSend.builder().build();
StarboardPost post = Mockito.mock(StarboardPost.class);
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(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);
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(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<>();
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);
}
@Test
public void testDeleteStarboardMessagePost() {
AServer server = MockUtils.getServer();
AChannel channel = MockUtils.getTextChannel(server, 4L);
Long messageId = 4L;
StarboardPost post = StarboardPost
.builder()
.starboardChannel(channel)
.sourceChanel(channel)
.starboardMessageId(messageId)
.build();
StarboardPost post = Mockito.mock(StarboardPost.class);
when(post.getStarboardMessageId()).thenReturn(messageId);
AChannel channel = Mockito.mock(AChannel.class);
when(channel.getServer()).thenReturn(server);
when(server.getId()).thenReturn(SERVER_ID);
when(channel.getId()).thenReturn(CHANNEL_ID);
when(post.getSourceChanel()).thenReturn(channel);
when(post.getStarboardChannel()).thenReturn(channel);
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)
public void testPersistingOfNotFoundStarredUser() {
AServer server = MockUtils.getServer();
AUserInAServer userReacting = MockUtils.getUserObject(4L, server);
AUserInAServer starredUser = MockUtils.getUserObject(5L, server);
when(userInServerManagementService.loadUserConditional(starredUser.getUserInServerId())).thenReturn(Optional.empty());
executeLoadErrorTest(server, userReacting, starredUser, 10L);
when(userInServerManagementService.loadUserOptional(SECOND_USER_IN_SERVER_ID)).thenReturn(Optional.empty());
CachedMessage message = Mockito.mock(CachedMessage.class);
List<Long> userExceptAuthorIds = Arrays.asList(FIRST_USER_IN_SERVER_ID);
List<CompletableFuture<Message>> futures = Arrays.asList(CompletableFuture.completedFuture(sendPost));
testUnit.persistPost(message, userExceptAuthorIds, futures, CHANNEL_ID, SECOND_USER_IN_SERVER_ID);
}
@Test
public void testRetrieveStarStats() {
AServer server = MockUtils.getServer();
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 secondPostMessageId = 51L;
StarboardPostReaction reaction = StarboardPostReaction.builder().build();
StarboardPost post1 = StarboardPost.builder().starboardChannel(channel).postMessageId(firstPostMessageId).reactions(Arrays.asList(reaction)).build();
StarboardPost post2 = StarboardPost.builder().starboardChannel(channel).postMessageId(secondPostMessageId).reactions(new ArrayList<>()).build();
StarboardPostReaction reaction = Mockito.mock(StarboardPostReaction.class);
StarboardPost post1 = Mockito.mock(StarboardPost.class);
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);
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> statsUser2 = CompletableFuture.completedFuture(Mockito.mock(StarStatsUser.class));
List<CompletableFuture<StarStatsUser>> topGiver = Arrays.asList(statsUser, statsUser2);
when(starboardPostReactorManagementService.retrieveTopStarGiver(server.getId(), limit)).thenReturn(topGiver);
when(starboardPostReactorManagementService.retrieveTopStarReceiver(server.getId(), limit)).thenReturn(topGiver);
when(starboardPostManagementService.getPostCount(server.getId())).thenReturn(50);
when(starboardPostReactorManagementService.getStarCount(server.getId())).thenReturn(500);
when(emoteService.getUsableEmoteOrDefault(server.getId(), "starboardBadge1")).thenReturn("1");
when(emoteService.getUsableEmoteOrDefault(server.getId(), "starboardBadge2")).thenReturn("2");
when(emoteService.getUsableEmoteOrDefault(server.getId(), "starboardBadge3")).thenReturn("3");
CompletableFuture<StarStatsModel> modelFuture = testUnit.retrieveStarStats(server.getId());
when(starboardPostReactorManagementService.retrieveTopStarGiver(SERVER_ID, limit)).thenReturn(topGiver);
when(starboardPostReactorManagementService.retrieveTopStarReceiver(SERVER_ID, limit)).thenReturn(topGiver);
when(starboardPostManagementService.getPostCount(SERVER_ID)).thenReturn(50);
when(starboardPostReactorManagementService.getStarCount(SERVER_ID)).thenReturn(500);
when(emoteService.getUsableEmoteOrDefault(SERVER_ID, "starboardBadge1")).thenReturn("1");
when(emoteService.getUsableEmoteOrDefault(SERVER_ID, "starboardBadge2")).thenReturn("2");
when(emoteService.getUsableEmoteOrDefault(SERVER_ID, "starboardBadge3")).thenReturn("3");
CompletableFuture<StarStatsModel> modelFuture = testUnit.retrieveStarStats(SERVER_ID);
StarStatsModel model = modelFuture.join();
List<String> badgeEmotes = model.getBadgeEmotes();
Assert.assertEquals(limit.intValue(), badgeEmotes.size());
@@ -278,28 +287,16 @@ public class StarboardServiceBeanTest {
Assert.assertEquals(500, model.getTotalStars().intValue());
Assert.assertEquals(50, model.getStarredMessages().intValue());
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(firstPostMessageId, topPost.getMessageId());
Assert.assertEquals(1, topPost.getStarCount().intValue());
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(secondPostMessageId, secondTopPost.getMessageId());
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;
import dev.sheldan.abstracto.core.models.cache.CachedAuthor;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AChannel;
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.models.database.EmbeddedMessage;
import dev.sheldan.abstracto.utility.repository.EmbeddedMessageRepository;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.entities.*;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -45,43 +44,53 @@ public class MessageEmbedPostManagementServiceBeanTest {
@Captor
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
public void testCreateCorrectEmbed(){
AServer server = MockUtils.getServer();
AUserInAServer embeddingUser = MockUtils.getUserObject(5L, server);
AUserInAServer embeddedUser = MockUtils.getUserObject(7L, server);
AChannel channel = MockUtils.getTextChannel(server, 8L);
when(serverManagementService.loadOrCreate(server.getId())).thenReturn(server);
when(channelManagementService.loadChannel(channel.getId())).thenReturn(channel);
Long embeddedMessageId = 5L;
Long embeddingMessageId = 7L;
CachedMessage cachedMessage = CachedMessage
.builder()
.messageId(embeddedMessageId)
.channelId(channel.getId())
.serverId(server.getId())
.authorId(embeddedUser.getUserReference().getId())
.build();
Message message = Mockito.mock(Message.class);
public void testCreateCorrectEmbed() {
AUserInAServer embeddingUser = Mockito.mock(AUserInAServer.class);
AUserInAServer embeddedUser = Mockito.mock(AUserInAServer.class);
AChannel channel = Mockito.mock(AChannel.class);
AServer server = Mockito.mock(AServer.class);
when(server.getId()).thenReturn(SERVER_ID);
when(serverManagementService.loadOrCreate(SERVER_ID)).thenReturn(server);
when(channelManagementService.loadChannel(EMBEDDING_CHANNEL_ID)).thenReturn(channel);
CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
when(cachedMessage.getMessageId()).thenReturn(EMBEDDED_MESSAGE_ID);
when(cachedMessage.getServerId()).thenReturn(SERVER_ID);
when(cachedMessage.getChannelId()).thenReturn(EMBEDDING_CHANNEL_ID);
CachedAuthor cachedAuthor = Mockito.mock(CachedAuthor.class);
when(cachedAuthor.getAuthorId()).thenReturn(EMBEDDED_USER_ID);
when(cachedMessage.getAuthor()).thenReturn(cachedAuthor);
when(cachedMessage.getServerId()).thenReturn(SERVER_ID);
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);
MessageChannel embeddedChannel = Mockito.mock(MessageChannel.class);
when(message.getChannel()).thenReturn(embeddedChannel);
when(message.getGuild()).thenReturn(guild);
when(guild.getIdLong()).thenReturn(server.getId());
when(message.getIdLong()).thenReturn(embeddingMessageId);
when(embeddedChannel.getIdLong()).thenReturn(channel.getId());
when(userInServerManagementService.loadUser(server.getId(), embeddedUser.getUserReference().getId())).thenReturn(embeddedUser);
testUnit.createMessageEmbed(cachedMessage, message, embeddingUser);
when(embeddingMessage.getGuild()).thenReturn(guild);
when(guild.getIdLong()).thenReturn(SERVER_ID);
when(embeddingMessage.getIdLong()).thenReturn(EMBEDDING_MESSAGE_ID);
when(userInServerManagementService.loadUser(SERVER_ID, EMBEDDED_USER_ID)).thenReturn(embeddedUser);
testUnit.createMessageEmbed(cachedMessage, embeddingMessage, embeddingUser);
verify(embeddedMessageRepository, times(1)).save(messageArgumentCaptor.capture());
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.getEmbeddingChannel());
Assert.assertEquals(embeddedUser, savedMessage.getEmbeddedUser());
Assert.assertEquals(embeddingUser, savedMessage.getEmbeddingUser());
Assert.assertEquals(server, savedMessage.getEmbeddedServer());
Assert.assertEquals(server, savedMessage.getEmbeddingServer());
Assert.assertEquals(embeddingMessageId, savedMessage.getEmbeddingMessageId());
Assert.assertEquals(EMBEDDING_MESSAGE_ID, savedMessage.getEmbeddingMessageId());
}
@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.repository.PostedImageRepository;
import dev.sheldan.abstracto.utility.service.RepostServiceBean;
import net.dv8tion.jda.api.entities.Message;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,12 +52,10 @@ public class PostedImageManagementBeanTest {
public void testCreatePost() {
AServerAChannelAUser serverAChannelAUser = Mockito.mock(AServerAChannelAUser.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.getChannel()).thenReturn(channel);
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(INDEX, createdPost.getPostId().getPosition());
Assert.assertEquals(MESSAGE_ID, createdPost.getPostId().getMessageId());

View File

@@ -1,5 +1,8 @@
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.utility.models.RepostLeaderboardEntryModel;
import dev.sheldan.abstracto.utility.models.database.PostedImage;
@@ -10,12 +13,14 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture;
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);
boolean isRepost(Message message, Message.Attachment attachment, Integer index);
Optional<PostedImage> getRepostFor(Message message, Message.Attachment attachment, Integer index);
boolean isRepost(CachedMessage message, CachedAttachment attachment, Integer index);
Optional<PostedImage> getRepostFor(CachedMessage message, CachedAttachment attachment, Integer index);
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);
CompletableFuture<List<RepostLeaderboardEntryModel>> retrieveRepostLeaderboard(Guild guild, Integer page);
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.AUserInAServer;
import dev.sheldan.abstracto.utility.models.database.PostedImage;
import net.dv8tion.jda.api.entities.Message;
import java.util.List;
import java.util.Optional;
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);
Optional<PostedImage> getPostWithHash(String hash, AServer server);
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.service.management.CommandInServerManagementService;
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 lombok.extern.slf4j.Slf4j;
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
public CompletableFuture<Parameters> getParametersForCommand(String commandName, Message messageContainingContent) {
String contentStripped = messageContainingContent.getContentRaw();
UnParsedCommandParameter unParsedParameter = new UnParsedCommandParameter(contentStripped);
UnParsedCommandParameter unParsedParameter = getUnParsedCommandParameter(contentStripped);
Command command = commandRegistry.findCommandByParameters(commandName, unParsedParameter);
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