replaced a bunch of places where the database loaded objects were referenced across threads, this might have lead to problems when lazy loading them

fixed starboard post template
fixed starboard post deletion
This commit is contained in:
Sheldan
2020-05-09 16:15:07 +02:00
parent 8db1cead57
commit da8fea34da
23 changed files with 181 additions and 122 deletions

View File

@@ -248,8 +248,8 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
}
@Transactional
public void sendUserReply(TextChannel textChannel, ModMailThread modMailThread, Message message) {
Long modMailThreadId = modMailThread.getId();
FullUser fullUser = FullUser
.builder()
.aUserInAServer(modMailThread.getUser())
@@ -275,15 +275,16 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_user_message", modMailUserReplyModel);
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, textChannel);
List<Message> messages = new ArrayList<>();
CompletableFuture.allOf(messages.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
self.postProcessSendMessages(modMailThread, message, completableFutures, messages);
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
self.postProcessSendMessages(modMailThreadId, message, completableFutures);
});
}
@Transactional
public void postProcessSendMessages(ModMailThread modMailThread, Message message, List<CompletableFuture<Message>> completableFutures, List<Message> messages) {
public void postProcessSendMessages(Long modMailThreadId, Message message, List<CompletableFuture<Message>> completableFutures) {
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
List<Message> messages = new ArrayList<>();
completableFutures.forEach(messageCompletableFuture -> {
try {
Message messageToAdd = messageCompletableFuture.get();
@@ -299,10 +300,11 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override
public void relayMessageToDm(ModMailThread modMailThread, String text, Message message, Boolean anonymous, MessageChannel feedBack) {
Long modMailThreadId = modMailThread.getId();
User userById = botService.getInstance().getUserById(modMailThread.getUser().getUserReference().getId());
if(userById != null) {
userById.openPrivateChannel().queue(privateChannel -> {
self.sendReply(modMailThread, text, message, privateChannel, anonymous, feedBack);
self.sendReply(modMailThreadId, text, message, privateChannel, anonymous, feedBack);
}, throwable -> {
log.warn("Failed to open private channel with user {}", userById.getIdLong());
});
@@ -332,11 +334,11 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override
public synchronized void closeModMailThread(ModMailThread modMailThread, MessageChannel feedBack, String note, Boolean notifyUser) {
Long modMailThreadId = modMailThread.getId();
log.info("Starting closing procedure for thread {}", modMailThread.getId());
List<ModMailMessage> modMailMessages = modMailThread.getMessages();
List<CompletableFuture<Message>> messages = modMailMessageService.loadModMailMessages(modMailMessages);
log.trace("Loading {} mod mail thread messages.", messages.size());
Long modMailThreadId = modMailThread.getId();
for (int i = 0; i < messages.size(); i++) {
CompletableFuture<Message> messageCompletableFuture = messages.get(i);
Long messageId = modMailMessages.get(i).getMessageId();
@@ -346,6 +348,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
});
}
CompletableFuture.allOf(messages.toArray(new CompletableFuture[0])).whenComplete((avoid, throwable) -> {
ModMailThread innerModMailThread = modMailThreadManagementService.getById(modMailThreadId);
log.trace("Loaded {} mod mail thread messages", messages.size());
if(throwable != null) {
log.warn("Failed to load some mod mail messages for mod mail thread {}. Still trying to post the ones we got.", modMailThreadId, throwable);
@@ -367,16 +370,16 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
self.afterSuccessfulLog(modMailThreadId, feedBack, notifyUser, undoActions);
});
list.getMainFuture().exceptionally(innerThrowable -> {
sendModMailFailure("modmail_exception_generic", modMailThread.getUser(), modMailThreadId, feedBack, innerThrowable);
sendModMailFailure("modmail_exception_generic", innerModMailThread.getUser(), modMailThreadId, feedBack, innerThrowable);
log.error("Failed to log messages for mod mail thread {}.", modMailThreadId, innerThrowable);
return null;
});
} catch (PostTargetException po) {
log.error("Failed to log mod mail messages", po);
sendModMailFailure("modmail_exception_post_target_not_defined", modMailThread.getUser(), modMailThreadId, feedBack, po);
sendModMailFailure("modmail_exception_post_target_not_defined", innerModMailThread.getUser(), modMailThreadId, feedBack, po);
} catch (Exception e) {
log.error("Failed to log mod mail messages", e);
sendModMailFailure("modmail_exception_generic", modMailThread.getUser(), modMailThreadId, feedBack, e);
sendModMailFailure("modmail_exception_generic", innerModMailThread.getUser(), modMailThreadId, feedBack, e);
}
});
@@ -507,7 +510,8 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
@Transactional
public void sendReply(ModMailThread modMailThread, String text, Message message, PrivateChannel privateChannel, Boolean anonymous, MessageChannel feedBack) {
public void sendReply(Long modMailThreadId, String text, Message message, PrivateChannel privateChannel, Boolean anonymous, MessageChannel feedBack) {
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember());
Member userInGuild = botService.getMemberInServer(modMailThread.getUser());
Member moderatorMember = botService.getMemberInServer(moderator);
@@ -532,19 +536,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_staff_message", modMailUserReplyModel);
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, privateChannel);
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
List<Message> messages = new ArrayList<>();
completableFutures.forEach(messageCompletableFuture -> {
try {
Message messageToAdd = messageCompletableFuture.get();
messages.add(messageToAdd);
} catch (InterruptedException | ExecutionException e) {
log.error("A future when sending the message to the user was interrupted.", e);
} catch (Exception e) {
log.error("Failed to handle the send staff message.", e);
}
});
self.saveMessageIds(messages, modMailThread, moderator, anonymous, true);
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.MOD_REPLIED);
self.saveSendMessagesAndUpdateState(modMailThreadId, anonymous, moderator, completableFutures);
}).exceptionally(throwable -> {
log.error("Failed to send message to user {}", modMailThread.getUser().getUserReference().getId());
sendModMailFailure("modmail_exception_cannot_message_user", modMailThread.getUser(), modMailThread.getId(), feedBack, throwable);
@@ -553,6 +545,23 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
@Transactional
public void saveSendMessagesAndUpdateState(Long modMailThreadId, Boolean anonymous, AUserInAServer moderator, List<CompletableFuture<Message>> completableFutures) {
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
List<Message> messages = new ArrayList<>();
completableFutures.forEach(messageCompletableFuture -> {
try {
Message messageToAdd = messageCompletableFuture.get();
messages.add(messageToAdd);
} catch (InterruptedException | ExecutionException e) {
log.error("A future when sending the message to the user was interrupted.", e);
} catch (Exception e) {
log.error("Failed to handle the send staff message.", e);
}
});
self.saveMessageIds(messages, modMailThread, moderator, anonymous, true);
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.MOD_REPLIED);
}
public void saveMessageIds(List<Message> messages, ModMailThread modMailThread, AUserInAServer author, Boolean anonymous, Boolean inDmChannel) {
messages.forEach(message -> {
modMailMessageManagementService.addMessageToThread(modMailThread, message, author, anonymous, inDmChannel);

View File

@@ -37,8 +37,11 @@ public class MessageEmbedListener implements MessageReceivedListener {
List<MessageEmbedLink> links = messageEmbedService.getLinksInMessage(messageRaw);
for (MessageEmbedLink messageEmbedLink : links) {
messageRaw = messageRaw.replace(messageEmbedLink.getWholeUrl(), "");
AUserInAServer cause = userInServerManagementService.loadUser(message.getMember());
Consumer<CachedMessage> cachedMessageConsumer = cachedMessage -> messageEmbedService.embedLink(cachedMessage, message.getTextChannel(), cause, message);
Long cause = userInServerManagementService.loadUser(message.getMember()).getUserInServerId();
Consumer<CachedMessage> cachedMessageConsumer = cachedMessage -> {
AUserInAServer userInAServer = userInServerManagementService.loadUser(cause);
messageEmbedService.embedLink(cachedMessage, message.getTextChannel(), userInAServer , message);
};
messageCache.getMessageFromCache(messageEmbedLink.getServerId(), messageEmbedLink.getChannelId(), messageEmbedLink.getMessageId()).thenAccept(cachedMessageConsumer)
.exceptionally(throwable -> {
log.error("Error when embedding link for message {}", message.getId(), throwable);

View File

@@ -55,9 +55,10 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
if(embeddedMessage.getEmbeddedUser().getUserReference().getId().equals(userReacting.getId())
|| embeddedMessage.getEmbeddingUser().getUserReference().getId().equals(userReacting.getId())
) {
messageService.deleteMessageInChannelInServer(message.getServerId(), message.getChannelId(), message.getMessageId()).thenAccept(aVoid ->
messageEmbedPostManagementService.deleteEmbeddedMessageTransactional(embeddedMessage)
);
messageService.deleteMessageInChannelInServer(message.getServerId(), message.getChannelId(), message.getMessageId()).thenAccept(aVoid ->{
Optional<EmbeddedMessage> innerOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId());
innerOptional.ifPresent(value -> messageEmbedPostManagementService.deleteEmbeddedMessageTransactional(value));
});
}
}

View File

@@ -6,7 +6,6 @@ import dev.sheldan.abstracto.core.listener.ReactedRemovedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReaction;
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;
@@ -76,40 +75,43 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
private void updateStarboardPost(CachedMessage message, CachedReaction reaction, AUserInAServer userReacting, boolean adding) {
Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId());
if(reaction != null) {
List<AUser> userExceptAuthor = getUsersExcept(reaction.getUsers(), message.getAuthorId());
AUserInAServer author = userInServerManagementService.loadUser(message.getServerId(), message.getAuthorId());
List<AUserInAServer> userExceptAuthor = getUsersExcept(reaction.getUserInServersIds(), author);
Double starMinimum = getFromConfig("starLvl1", message.getServerId());
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());
AUserInAServer author = userInServerManagementService.loadUser(message.getServerId(), message.getAuthorId());
if(starboardPostOptional.isPresent()) {
StarboardPost starboardPost = starboardPostOptional.get();
starboardPost.setIgnored(false);
starboardService.updateStarboardPost(starboardPost, message, userExceptAuthor);
if(adding) {
log.trace("Adding reactor {} from message {}", userReacting.getUserReference().getId(), message.getMessageId());
starboardPostReactorManagementService.addReactor(starboardPost, userReacting.getUserReference());
starboardPostReactorManagementService.addReactor(starboardPost, userReacting);
} else {
log.trace("Removing reactor {} from message {}", userReacting.getUserReference().getId(), message.getMessageId());
starboardPostReactorManagementService.removeReactor(starboardPost, userReacting.getUserReference());
starboardPostReactorManagementService.removeReactor(starboardPost, userReacting);
}
} else {
log.info("Creating starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId());
starboardService.createStarboardPost(message, userExceptAuthor, userReacting, author);
}
} else {
log.info("Removing starboard post for message {} in channel {} in server {}. It fell under the threshold {}", message.getMessageId(), message.getChannelId(), message.getServerId(), starMinimum);
starboardPostOptional.ifPresent(this::completelyRemoveStarboardPost);
if(starboardPostOptional.isPresent()) {
log.info("Removing starboard post for message {} in channel {} in server {}. It fell under the threshold {}", message.getMessageId(), message.getChannelId(), message.getServerId(), starMinimum);
starboardPostOptional.ifPresent(this::completelyRemoveStarboardPost);
}
}
} else {
log.info("Removing starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId());
starboardPostOptional.ifPresent(this::completelyRemoveStarboardPost);
if(starboardPostOptional.isPresent()) {
log.info("Removing starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId());
starboardPostOptional.ifPresent(this::completelyRemoveStarboardPost);
}
}
}
private void completelyRemoveStarboardPost(StarboardPost starboardPost) {
starboardPostReactorManagementService.removeReactors(starboardPost);
starboardService.removeStarboardPost(starboardPost);
starboardService.deleteStarboardMessagePost(starboardPost);
starboardPostManagementService.removePost(starboardPost);
}
@@ -127,7 +129,7 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
log.trace("User {} in server {} removed star reaction from message {} on starboard.",
userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), message.getMessageId());
Optional<CachedReaction> reactionOptional = EmoteUtils.getReactionFromMessageByEmote(message, aEmote);
updateStarboardPost(message, reactionOptional.orElse(null), userRemoving, false);
updateStarboardPost(message, reactionOptional.orElse(null), userRemoving, false);
}
}
@@ -135,8 +137,8 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
return configManagementService.loadConfig(guildId, key).getDoubleValue();
}
private List<AUser> getUsersExcept(List<AUser> users, Long userId) {
return users.stream().filter(user -> !user.getId().equals(userId)).collect(Collectors.toList());
private List<AUserInAServer> getUsersExcept(List<Long> users, AUserInAServer author) {
return users.stream().filter(user -> !user.equals(author.getUserInServerId())).map(aLong -> userInServerManagementService.loadUser(aLong)).collect(Collectors.toList());
}
@Override

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.repository;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.models.database.StarboardPostReaction;
import org.springframework.data.jpa.repository.JpaRepository;
@@ -13,7 +13,7 @@ import java.util.List;
public interface StarboardPostReactionRepository extends JpaRepository<StarboardPostReaction, Long> {
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
void deleteByReactorAndStarboardPost(AUser user, StarboardPost post);
void deleteByReactorAndStarboardPost(AUserInAServer user, StarboardPost post);
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
void deleteByStarboardPost(StarboardPost post);

View File

@@ -97,15 +97,18 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
@Override
public void embedLinks(List<MessageEmbedLink> linksToEmbed, TextChannel target, AUserInAServer reason, Message embeddingMessage) {
linksToEmbed.forEach(messageEmbedLink ->
linksToEmbed.forEach(messageEmbedLink -> {
Long userInServerId = reason.getUserInServerId();
messageCache.getMessageFromCache(messageEmbedLink.getServerId(), messageEmbedLink.getChannelId(), messageEmbedLink.getMessageId())
.thenAccept(cachedMessage ->
self.embedLink(cachedMessage, target, reason, embeddingMessage)
.thenAccept(cachedMessage -> {
AUserInAServer cause = userInServerManagementService.loadUser(userInServerId);
self.embedLink(cachedMessage, target, cause, embeddingMessage);
}
).exceptionally(throwable -> {
log.error("Message retrieval from cache failed for message {}.", messageEmbedLink.getMessageId(), throwable);
return null;
})
);
});
});
}
@Override
@@ -116,10 +119,11 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(embed, target);
log.trace("Embedding message {} from channel {} from server {}, because of user {}", cachedMessage.getMessageId(),
cachedMessage.getChannelId(), cachedMessage.getServerId(), cause.getUserReference().getId());
Long userInServerId = cause.getUserInServerId();
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
try {
Message createdMessage = completableFutures.get(0).get();
messageEmbedPostManagementService.createMessageEmbed(cachedMessage, createdMessage, cause);
messageEmbedPostManagementService.createMessageEmbed(cachedMessage, createdMessage, userInServerManagementService.loadUser(userInServerId));
messageService.addReactionToMessage(REMOVAL_EMOTE, cachedMessage.getServerId(), createdMessage);
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post message embed.", e);

View File

@@ -1,9 +1,11 @@
package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.PostTargetManagement;
import dev.sheldan.abstracto.core.models.AServerAChannelMessage;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.*;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.ConfigService;
@@ -22,6 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.*;
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;
@@ -62,31 +65,33 @@ public class StarboardServiceBean implements StarboardService {
@Autowired
private PostTargetManagement postTargetManagement;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private EmoteService emoteService;
@Autowired
private StarboardServiceBean self;
@Override
public void createStarboardPost(CachedMessage message, List<AUser> userExceptAuthor, AUserInAServer userReacting, AUserInAServer starredUser) {
public void createStarboardPost(CachedMessage message, List<AUserInAServer> userExceptAuthor, AUserInAServer userReacting, AUserInAServer starredUser) {
StarboardPostModel starboardPostModel = buildStarboardPostModel(message, userExceptAuthor.size());
List<Long> userExceptAuthorIds = new ArrayList<>();
userExceptAuthor.forEach(aUserInAServer -> {
userExceptAuthorIds.add(aUserInAServer.getUserInServerId());
});
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARBOARD_POST_TEMPLATE, starboardPostModel);
PostTarget starboard = postTargetManagement.getPostTarget(STARBOARD_POSTTARGET, message.getServerId());
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, STARBOARD_POSTTARGET, message.getServerId());
Long starboardChannelId = starboard.getChannelReference().getId();
Long starredUserId = starredUser.getUserInServerId();
Long userReactingId = userReacting.getUserInServerId();
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
try {
Message message1 = completableFutures.get(0).get();
AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage
.builder()
.messageId(message1.getIdLong())
.channel(starboard.getChannelReference())
.server(userReacting.getServerReference())
.build();
StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, starredUser, userReacting, aServerAChannelMessage);
userExceptAuthor.forEach(user ->
starboardPostReactorManagementService.addReactor(starboardPost, user)
);
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post messages.", e);
}
self.persistPost(message, userExceptAuthorIds, completableFutures, starboardChannelId, starredUserId, userReactingId);
}) .exceptionally(throwable -> {
log.error("Failed to create starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId(), throwable);
return null;
@@ -94,6 +99,29 @@ public class StarboardServiceBean implements StarboardService {
}
@Transactional
public void persistPost(CachedMessage message, List<Long> userExceptAuthorIds, List<CompletableFuture<Message>> completableFutures, Long starboardChannelId, Long starredUserId, Long userReactingId) {
AUserInAServer innerStarredUser = userInServerManagementService.loadUser(starredUserId);
AUserInAServer innerUserReacting = userInServerManagementService.loadUser(userReactingId);
try {
AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId);
Message message1 = completableFutures.get(0).get();
AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage
.builder()
.messageId(message1.getIdLong())
.channel(starboardChannel)
.server(starboardChannel.getServer())
.build();
StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, innerStarredUser, innerUserReacting, aServerAChannelMessage);
userExceptAuthorIds.forEach(aLong -> {
AUserInAServer user = userInServerManagementService.loadUser(aLong);
starboardPostReactorManagementService.addReactor(starboardPost, user);
});
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post messages.", e);
}
}
private StarboardPostModel buildStarboardPostModel(CachedMessage message, Integer starCount) {
Member member = botService.getMemberInServer(message.getServerId(), message.getAuthorId());
Optional<TextChannel> channel = botService.getTextChannelFromServer(message.getServerId(), message.getChannelId());
@@ -117,14 +145,19 @@ public class StarboardServiceBean implements StarboardService {
}
@Override
public void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUser> userExceptAuthor) {
public void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUserInAServer> userExceptAuthor) {
StarboardPostModel starboardPostModel = buildStarboardPostModel(message, userExceptAuthor.size());
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARBOARD_POST_TEMPLATE, starboardPostModel);
List<CompletableFuture<Message>> futures = new ArrayList<>();
futures.add(new CompletableFuture<>());
postTargetService.editOrCreatedInPostTarget(post.getStarboardMessageId(), messageToSend, STARBOARD_POSTTARGET, message.getServerId(), futures);
Long starboardPostId = post.getId();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
try {
starboardPostManagementService.setStarboardPostMessageId(post, futures.get(0).get().getIdLong());
Optional<StarboardPost> innerPost = starboardPostManagementService.findByStarboardPostId(starboardPostId);
if(innerPost.isPresent()) {
starboardPostManagementService.setStarboardPostMessageId(innerPost.get(), futures.get(0).get().getIdLong());
}
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post starboard post.", e);
}
@@ -135,7 +168,7 @@ public class StarboardServiceBean implements StarboardService {
}
@Override
public void removeStarboardPost(StarboardPost message) {
public void deleteStarboardMessagePost(StarboardPost message) {
AChannel starboardChannel = message.getStarboardChannel();
botService.deleteMessage(starboardChannel.getServer().getId(), starboardChannel.getId(), message.getStarboardMessageId());
}

View File

@@ -56,6 +56,7 @@ public class SuggestionServiceBean implements SuggestionService {
Suggestion suggestion = suggestionManagementService.createSuggestion(member, text);
suggestionLog.setSuggestion(suggestion);
suggestionLog.setText(text);
Long suggestionId = suggestion.getId();
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_LOG_TEMPLATE, suggestionLog);
long guildId = member.getGuild().getIdLong();
JDA instance = botService.getInstance();
@@ -63,16 +64,17 @@ public class SuggestionServiceBean implements SuggestionService {
if(guildById != null) {
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SUGGESTIONS_TARGET, guildId);
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
Suggestion innerSuggestion = suggestionManagementService.getSuggestion(suggestionId);
try {
Message message = completableFutures.get(0).get();
suggestionManagementService.setPostedMessage(suggestion, message);
suggestionManagementService.setPostedMessage(innerSuggestion, message);
messageService.addReactionToMessage(SUGGESTION_YES_EMOTE, guildId, message);
messageService.addReactionToMessage(SUGGESTION_NO_EMOTE, guildId, message);
} catch (InterruptedException | ExecutionException e) {
log.warn("Failed to post suggestion", e);
}
}) .exceptionally(throwable -> {
log.error("Failed to post suggestion {}", suggestion.getId(), throwable);
log.error("Failed to post suggestion {}", suggestionId, throwable);
return null;
});
} else {

View File

@@ -84,7 +84,7 @@ public class StarboardPostManagementServiceBean implements StarboardPostManageme
@Override
public void removePost(StarboardPost starboardPost) {
repository.deleteById(starboardPost.getId());
repository.delete(starboardPost);
}

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.service.management;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.models.database.StarboardPostReaction;
import dev.sheldan.abstracto.utility.models.template.commands.starboard.StarStatsUser;
@@ -22,7 +22,7 @@ public class StarboardPostReactorManagementServiceBean implements StarboardPostR
private StarStatsUserConverter converter;
@Override
public void addReactor(StarboardPost post, AUser user) {
public void addReactor(StarboardPost post, AUserInAServer user) {
StarboardPostReaction reactor = StarboardPostReaction
.builder()
.starboardPost(post)
@@ -32,7 +32,7 @@ public class StarboardPostReactorManagementServiceBean implements StarboardPostR
}
@Override
public void removeReactor(StarboardPost post, AUser user) {
public void removeReactor(StarboardPost post, AUserInAServer user) {
repository.deleteByReactorAndStarboardPost(user, post);
}

View File

@@ -11,37 +11,37 @@
"r": 200,
"g": 0,
"b": 255
},
}
<#if message.content?has_content || message.embeds?size gt 0>
"description": "${message.content}
,"description": "${message.content}
<#list message.embeds>
<#include "starboard_post_embed_embeds_name">:
<#items as embed>
<#include "starboard_post_embed_description">: ${embed.description} <#if embed.imageUrl?has_content> <#include "starboard_post_embed_image_url">: ${embed.imageUrl} </#if>
</#items>
</#list>
",
"
</#if>
<#assign emote>${starLevelEmote}</#assign>
<#assign count>${starCount}</#assign>
<#assign messageId>${message.messageId?c}</#assign>
<#if channel?has_content>
<#assign channel>${channel.asMention}</#assign>
"additionalMessage": "<#include "starboard_post_embed_additional_message">",
<#assign channelMention>${channel.asMention}</#assign>
,"additionalMessage": "<#include "starboard_post_embed_additional_message">"
<#else>
<#assign channel>${aChannel.id?c}</#assign>
"additionalMessage": "<#include "starboard_post_embed_additional_message">",
<#assign channelMention>${aChannel.id?c}</#assign>
,"additionalMessage": "<#include "starboard_post_embed_additional_message">"
</#if>
<#if message.attachmentUrls?size gt 0>
"imageUrl": "${message.attachmentUrls[0]}",
,"imageUrl": "${message.attachmentUrls[0]}"
</#if>
"fields": [
,"fields": [
{
"name": "<#include "starboard_post_embed_original_field_title">",
"name": "<#include "starboard_post_embed_original_field_title">"
<#if channel?has_content>
"value": "[${channel.name}](${message.messageUrl})"
,"value": "[${channel.name}](${message.messageUrl})"
<#else>
"value": "[${aChannel.id?c}](${message.messageUrl})"
,"value": "[${aChannel.id?c}](${message.messageUrl})"
</#if>
}
],

View File

@@ -54,8 +54,8 @@ public class StarboardPost {
@Getter
@OneToMany(fetch = FetchType.LAZY,
orphanRemoval = true,
cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name="postId")
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE},
mappedBy = "starboardPost")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<StarboardPostReaction> reactions;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.models.database;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import lombok.*;
import org.hibernate.annotations.CacheConcurrencyStrategy;
@@ -24,10 +24,11 @@ public class StarboardPostReaction {
@ManyToOne
@JoinColumn(name = "reactorId", nullable = false)
private AUser reactor;
private AUserInAServer reactor;
@OneToOne
@JoinColumn(name = "postId", nullable = false)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private StarboardPost starboardPost;
@Override

View File

@@ -1,7 +1,6 @@
package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.models.template.commands.starboard.StarStatsModel;
@@ -9,8 +8,8 @@ import dev.sheldan.abstracto.utility.models.template.commands.starboard.StarStat
import java.util.List;
public interface StarboardService {
void createStarboardPost(CachedMessage message, List<AUser> userExceptAuthor, AUserInAServer userReacting, AUserInAServer starredUser);
void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUser> userExceptAuthor);
void removeStarboardPost(StarboardPost message);
void createStarboardPost(CachedMessage message, List<AUserInAServer> userExceptAuthor, AUserInAServer userReacting, AUserInAServer starredUser);
void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUserInAServer> userExceptAuthor);
void deleteStarboardMessagePost(StarboardPost message);
StarStatsModel retrieveStarStats(Long serverId);
}

View File

@@ -1,14 +1,14 @@
package dev.sheldan.abstracto.utility.service.management;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.models.template.commands.starboard.StarStatsUser;
import java.util.List;
public interface StarboardPostReactorManagementService {
void addReactor(StarboardPost post, AUser user);
void removeReactor(StarboardPost post, AUser user);
void addReactor(StarboardPost post, AUserInAServer user);
void removeReactor(StarboardPost post, AUserInAServer user);
void removeReactors(StarboardPost post);
Integer getStarCount(Long serverId);
List<StarStatsUser> retrieveTopStarGiver(Long serverId, Integer count);

View File

@@ -29,7 +29,6 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -65,7 +64,6 @@ public class CommandReceivedHandler extends ListenerAdapter {
private RoleManagementService roleManagementService;
@Override
@Async
@Transactional
public void onMessageReceived(@Nonnull MessageReceivedEvent event) {
if(!event.isFromGuild()) {

View File

@@ -7,7 +7,6 @@ import dev.sheldan.abstracto.core.service.FeatureFlagService;
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.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.MessageCache;
import dev.sheldan.abstracto.core.utils.EmoteUtils;
@@ -73,7 +72,7 @@ public class ReactionUpdatedListener extends ListenerAdapter {
});
}
private void addReactionIfNotThere(CachedMessage message, CachedReaction reaction, AUser userReacting) {
private void addReactionIfNotThere(CachedMessage message, CachedReaction reaction, AUserInAServer userReacting) {
Optional<CachedReaction> existingReaction = message.getReactions().stream().filter(reaction1 ->
EmoteUtils.compareAEmote(reaction1.getEmote(), reaction.getEmote())
).findAny();
@@ -81,28 +80,28 @@ public class ReactionUpdatedListener extends ListenerAdapter {
message.getReactions().add(reaction);
} else {
CachedReaction cachedReaction = existingReaction.get();
Optional<AUser> any = cachedReaction.getUsers().stream().filter(user -> user.getId().equals(userReacting.getId())).findAny();
Optional<Long> any = cachedReaction.getUserInServersIds().stream().filter(user -> user.equals(userReacting.getUserInServerId())).findAny();
if(!any.isPresent()){
cachedReaction.getUsers().add(userReacting);
cachedReaction.getUserInServersIds().add(userReacting.getUserInServerId());
}
}
}
private void removeReactionIfThere(CachedMessage message, CachedReaction reaction, AUser userReacting) {
private void removeReactionIfThere(CachedMessage message, CachedReaction reaction, AUserInAServer userReacting) {
Optional<CachedReaction> existingReaction = message.getReactions().stream().filter(reaction1 ->
EmoteUtils.compareAEmote(reaction1.getEmote(), reaction.getEmote())
).findAny();
if(existingReaction.isPresent()) {
CachedReaction cachedReaction = existingReaction.get();
cachedReaction.getUsers().removeIf(user -> user.getId().equals(userReacting.getId()));
message.getReactions().removeIf(reaction1 -> reaction1.getUsers().isEmpty());
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.getUserReference());
addReactionIfNotThere(cachedMessage, reaction, userInAServer);
addedListenerList.forEach(reactedAddedListener -> {
FeatureConfig feature = featureFlagService.getFeatureDisplayForFeature(reactedAddedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
@@ -143,7 +142,7 @@ public class ReactionUpdatedListener extends ListenerAdapter {
@Transactional
public void callRemoveListeners(@Nonnull GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, CachedReaction reaction) {
AUserInAServer userInAServer = userInServerManagementService.loadUser(event.getGuild().getIdLong(), event.getUserIdLong());
removeReactionIfThere(cachedMessage, reaction, userInAServer.getUserReference());
removeReactionIfThere(cachedMessage, reaction, userInAServer);
reactionRemovedListener.forEach(reactionRemovedListener -> {
FeatureConfig feature = featureFlagService.getFeatureDisplayForFeature(reactionRemovedListener.getFeature());
if(!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {

View File

@@ -4,8 +4,8 @@ import dev.sheldan.abstracto.core.exception.ChannelException;
import dev.sheldan.abstracto.core.exception.GuildException;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.cache.CachedReaction;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.cache.*;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.requests.restaction.pagination.ReactionPaginationAction;
@@ -36,6 +36,9 @@ public class MessageCacheBean implements MessageCache {
@Autowired
private EmoteService emoteService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
@Lazy
// needs to be lazy, because of circular dependency
@@ -51,7 +54,8 @@ public class MessageCacheBean implements MessageCache {
}
@CachePut(key = "#message.messageId")
@Override
@CachePut(key = "#message.messageId.toString()")
public CompletableFuture<CachedMessage> putMessageInCache(CachedMessage message) {
log.info("Adding cached message to cache");
return CompletableFuture.completedFuture(message);
@@ -74,7 +78,6 @@ public class MessageCacheBean implements MessageCache {
return cachedMessageCompletableFuture;
}
@Async
@Override
public void loadMessage(CompletableFuture<CachedMessage> future, Long guildId, Long textChannelId, Long messageId) {
Optional<Guild> guildOptional = botService.getGuildById(guildId);
@@ -97,7 +100,6 @@ public class MessageCacheBean implements MessageCache {
}
@Override
@Async
public void buildCachedMessageFromMessage(CompletableFuture<CachedMessage> future, Message message) {
List<String> attachmentUrls = new ArrayList<>();
message.getAttachments().forEach(attachment ->
@@ -147,21 +149,22 @@ public class MessageCacheBean implements MessageCache {
}
@Override
@Async
public void getCachedReactionFromReaction(CompletableFuture<CachedReaction> future, MessageReaction reaction) {
ReactionPaginationAction users = reaction.retrieveUsers().cache(false);
CachedReaction.CachedReactionBuilder builder = CachedReaction.builder();
List<AUser> ausers = new ArrayList<>();
List<Long> ausers = new ArrayList<>();
users.forEachAsync(user -> {
ausers.add(AUser.builder().id(user.getIdLong()).build());
if(reaction.getGuild() != null) {
ausers.add(userInServerManagementService.loadUser(reaction.getGuild().getIdLong(), user.getIdLong()).getUserInServerId());
}
return false;
}).thenAccept(o -> future.complete(builder.build()))
.exceptionally(throwable -> {
log.error("Failed to load reaction users.", throwable);
return null;
});
builder.users(ausers);
builder.userInServersIds(ausers);
builder.emote(emoteService.buildAEmoteFromReaction(reaction.getReactionEmote()));
}

View File

@@ -46,6 +46,11 @@ public class UserInServerManagementServiceBean implements UserInServerManagement
return this.loadUser(member.getGuild().getIdLong(), member.getIdLong());
}
@Override
public AUserInAServer loadUser(Long userInServerId) {
return userInServerRepository.getOne(userInServerId);
}
@Override
public AUserInAServer createUserInServer(Member member) {
return this.createUserInServer(member.getGuild().getIdLong(), member.getIdLong());

View File

@@ -1,7 +1,6 @@
package dev.sheldan.abstracto.core.models.cache;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.AUser;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@@ -13,5 +12,5 @@ import java.util.List;
@Builder
public class CachedReaction {
private AEmote emote;
private List<AUser> users;
private List<Long> userInServersIds;
}

View File

@@ -11,6 +11,7 @@ public interface UserInServerManagementService {
AUserInAServer loadUser(Long serverId, Long userId);
AUserInAServer loadUser(AServer server, AUser user);
AUserInAServer loadUser(Member member);
AUserInAServer loadUser(Long userInServerId);
AUserInAServer createUserInServer(Member member);
AUserInAServer createUserInServer(Long guildId, Long userId);
List<AUserInAServer> getUserInAllServers(Long userId);

View File

@@ -1 +1 @@
${emote} ${count} ${channel} ID: ${messageId}",
${emote} ${count} ${channelMention} ID: ${messageId}