[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>