mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-20 06:48:20 +00:00
Compare commits
15 Commits
abstracto-
...
abstracto-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d27c487f2 | ||
|
|
8ac3b327e4 | ||
|
|
448332f24f | ||
|
|
d7f889971d | ||
|
|
69abff77fb | ||
|
|
2c31fa1c1e | ||
|
|
19a4858da1 | ||
|
|
3ed1f0c54a | ||
|
|
d01e46a9a6 | ||
|
|
222250b795 | ||
|
|
9a87b75998 | ||
|
|
b16cef0d3c | ||
|
|
cc55934ff2 | ||
|
|
168b4a52c8 | ||
|
|
73b5684a7e |
@@ -14,7 +14,7 @@ An example implementation of this bot can be seen [here](https://github.com/Shel
|
||||
|
||||
|
||||
## Technologies
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 4.3.0_284
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 4.3.0_315
|
||||
* [Spring boot](https://github.com/spring-projects/spring-boot) is used as a framework to create standalone application in Java with Java EE methods. (including Dependency injection and more)
|
||||
* [Hibernate](https://github.com/hibernate/hibernate-orm) is used as a reference implementation of JPA.
|
||||
* [Freemarker](https://github.com/apache/freemarker) is used as a templating engine. This is used to provide internationalization for user facing text and enable dynamic embed configuration.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -149,6 +149,9 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene
|
||||
self.persistAssignableUser(member, payload, false);
|
||||
});
|
||||
}
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to perform role change in assignable role place.", throwable);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
assignableRoleService.removeAssignableRoleFromUser(roleById, member)
|
||||
|
||||
@@ -205,16 +205,15 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
if (throwable != null) {
|
||||
log.warn("Not able to delete old messages of assignable role place {} in server {}.", assignablePlaceId, serverId);
|
||||
}
|
||||
try {
|
||||
self.createAssignableRolePlacePost(serverId, assignablePlaceId)
|
||||
.thenAccept(unused1 -> postingFuture.complete(null))
|
||||
.exceptionally(innerThrowable -> {
|
||||
postingFuture.completeExceptionally(innerThrowable);
|
||||
return null;
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
postingFuture.completeExceptionally(ex);
|
||||
}
|
||||
self.createAssignableRolePlacePost(serverId, assignablePlaceId)
|
||||
.thenAccept(unused1 -> postingFuture.complete(null))
|
||||
.exceptionally(innerThrowable -> {
|
||||
postingFuture.completeExceptionally(innerThrowable);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
postingFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
return postingFuture;
|
||||
}
|
||||
@@ -361,17 +360,16 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
if (throwable != null) {
|
||||
log.warn("Not able to delete old messages of assignable role place {} in server {}.", assignablePlaceId, serverId);
|
||||
}
|
||||
try {
|
||||
self.setupAssignableRolePlaceInChannel(serverId, assignablePlaceId, newChannel)
|
||||
.thenAccept(unused1 -> self.updateAssignableRolePlaceChannel(name, newChannel))
|
||||
.thenAccept(unused1 -> returnFuture.complete(null))
|
||||
.exceptionally(innerThrowable -> {
|
||||
returnFuture.completeExceptionally(innerThrowable);
|
||||
return null;
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
returnFuture.completeExceptionally(ex);
|
||||
}
|
||||
self.setupAssignableRolePlaceInChannel(serverId, assignablePlaceId, newChannel)
|
||||
.thenAccept(unused1 -> self.updateAssignableRolePlaceChannel(name, newChannel))
|
||||
.thenAccept(unused1 -> returnFuture.complete(null))
|
||||
.exceptionally(innerThrowable -> {
|
||||
returnFuture.completeExceptionally(innerThrowable);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
returnFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
|
||||
return returnFuture;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>assignable-roles-int</artifactId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>experience-tracking</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -37,16 +37,18 @@ public class JoiningUserRoleListener implements AsyncJoinListener {
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MemberJoinModel model) {
|
||||
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(model.getServerId(), model.getJoiningUser().getUserId());
|
||||
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(userInAServer.getUserInServerId());
|
||||
if(userExperienceOptional.isPresent()) {
|
||||
log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", model.getJoiningUser().getUserId(), model.getServerId());
|
||||
userExperienceService.syncForSingleUser(userExperienceOptional.get()).thenAccept(result ->
|
||||
log.info("Finished re-assigning experience for re-joining user {} in server {}.", model.getJoiningUser().getUserId(), model.getServerId())
|
||||
);
|
||||
} else {
|
||||
log.info("Joined user {} in server {} does not have any previous experience. Not setting up anything.", model.getJoiningUser().getUserId(), model.getServerId());
|
||||
}
|
||||
Optional<AUserInAServer> userInAServerOptional = userInServerManagementService.loadUserOptional(model.getServerId(), model.getJoiningUser().getUserId());
|
||||
userInAServerOptional.ifPresent(aUserInAServer -> {
|
||||
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(aUserInAServer.getUserInServerId());
|
||||
if(userExperienceOptional.isPresent()) {
|
||||
log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", model.getJoiningUser().getUserId(), model.getServerId());
|
||||
userExperienceService.syncForSingleUser(userExperienceOptional.get()).thenAccept(result ->
|
||||
log.info("Finished re-assigning experience for re-joining user {} in server {}.", model.getJoiningUser().getUserId(), model.getServerId())
|
||||
);
|
||||
} else {
|
||||
log.info("Joined user {} in server {} does not have any previous experience. Not setting up anything.", model.getJoiningUser().getUserId(), model.getServerId());
|
||||
}
|
||||
});
|
||||
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
|
||||
@@ -166,6 +166,9 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
FutureUtils.toSingleFutureGeneric(memberFutures).whenComplete((unused, throwable) -> {
|
||||
self.updateFoundMembers(memberFutures, serverExp.getServerId(), resultFutures, futures);
|
||||
experienceFuture.complete(null);
|
||||
}).exceptionally(throwable -> {
|
||||
experienceFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
return experienceFuture
|
||||
|
||||
@@ -39,7 +39,6 @@ public class HasLevelCondition implements SystemCondition {
|
||||
Map<String, Object> parameters = conditionContext.getParameters();
|
||||
Long userInServerId = (Long) parameters.get(USER_IN_SERVER_ID_VARIABLE_KEY);
|
||||
Integer level = (Integer) parameters.get(LEVEL_VARIABLE);
|
||||
log.info("Evaluating has level condition.");
|
||||
Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserOptional(userInServerId);
|
||||
if(userInServerOptional.isPresent()) {
|
||||
AUserInAServer userInServer = userInServerOptional.get();
|
||||
@@ -50,7 +49,7 @@ public class HasLevelCondition implements SystemCondition {
|
||||
log.info("Condition evaluated to {}", conditionResult);
|
||||
return conditionResult;
|
||||
}
|
||||
log.info("No user in server object was found. Evaluating to false.");
|
||||
log.info("No user in server object was found. Evaluating has level to false.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class JoiningUserRoleListenerTest {
|
||||
when(model.getJoiningUser()).thenReturn(serverUser);
|
||||
when(model.getServerId()).thenReturn(SERVER_ID);
|
||||
when(aUserInAServer.getUserInServerId()).thenReturn(USER_IN_SERVER_ID);
|
||||
when(userInServerManagementService.loadOrCreateUser(SERVER_ID, USER_ID)).thenReturn(aUserInAServer);
|
||||
when(userInServerManagementService.loadUserOptional(SERVER_ID, USER_ID)).thenReturn(Optional.of(aUserInAServer));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>experience-tracking</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>invite-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -325,6 +325,9 @@ public class InviteLinkFilterServiceBean implements InviteLinkFilterService {
|
||||
sendDeletionNotification(deletedInvites, message);
|
||||
}
|
||||
}
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Invite matching failed.", throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>invite-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>link-embed</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ public class MessageEmbedListener implements MessageReceivedListener {
|
||||
log.debug("We found {} links to embed in message {} in channel {} in guild {}.", links.size(), message.getId(), message.getChannel().getId(), message.getGuild().getId());
|
||||
Long userEmbeddingUserInServerId = userInServerManagementService.loadOrCreateUser(message.getMember()).getUserInServerId();
|
||||
for (MessageEmbedLink messageEmbedLink : links) {
|
||||
// potentially support foreign linked servers
|
||||
if(!messageEmbedLink.getServerId().equals(message.getGuild().getIdLong())) {
|
||||
log.info("Link for message {} was from a foreign server {}. Do not embed.", messageEmbedLink.getMessageId(), messageEmbedLink.getServerId());
|
||||
continue;
|
||||
|
||||
@@ -168,6 +168,12 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
|
||||
.stream()
|
||||
.map(EmbeddedMessage::getEmbeddingMessageId)
|
||||
.collect(Collectors.toList());
|
||||
List<String> componentPayloadsToDelete = embeddedMessages
|
||||
.stream()
|
||||
.map(EmbeddedMessage::getDeletionComponentId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
List<CompletableFuture<Message>> reactionMessageFutures = messageService.retrieveMessages(reactionChannelMessages);
|
||||
List<CompletableFuture<Message>> buttonMessageFutures = messageService.retrieveMessages(buttonChannelMessages);
|
||||
CompletableFutureList<Message> reactionFutureList = new CompletableFutureList<>(reactionMessageFutures);
|
||||
@@ -193,7 +199,7 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
|
||||
if(throwable != null) {
|
||||
log.warn("Embedded message button clearing failed.", throwable);
|
||||
}
|
||||
self.deleteEmbeddedMessages(embeddedMessagesHandled);
|
||||
self.deleteEmbeddedMessages(embeddedMessagesHandled, componentPayloadsToDelete);
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
log.error("Failed to clean up embedded messages.", throwable);
|
||||
@@ -231,8 +237,9 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteEmbeddedMessages(List<Long> embeddedMessagesToDelete) {
|
||||
public void deleteEmbeddedMessages(List<Long> embeddedMessagesToDelete, List<String> componentPayloadsToDelete) {
|
||||
messageEmbedPostManagementService.deleteEmbeddedMessagesViaId(embeddedMessagesToDelete);
|
||||
componentPayloadManagementService.deletePayloads(componentPayloadsToDelete);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -309,6 +316,9 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
|
||||
.builder()
|
||||
.buttonId(deletionButtonEnabled ? componentServiceBean.generateComponentId() : null)
|
||||
.build();
|
||||
|
||||
Long referencedMessageId = message.getReferencedMessage() != null ? message.getReferencedMessage().getIdLong() : null;
|
||||
Boolean shouldMentionReferencedAuthor = shouldMentionReferencedAuthor(message);
|
||||
return MessageEmbeddedModel
|
||||
.builder()
|
||||
.member(message.getMember())
|
||||
@@ -319,7 +329,16 @@ public class MessageEmbedServiceBean implements MessageEmbedService {
|
||||
.guild(message.getGuild())
|
||||
.useButton(deletionButtonEnabled)
|
||||
.embeddedMessage(embeddedMessage)
|
||||
.referencedMessageId(referencedMessageId)
|
||||
.mentionsReferencedMessage(shouldMentionReferencedAuthor)
|
||||
.buttonConfigModel(buttonConfigModel)
|
||||
.build();
|
||||
}
|
||||
|
||||
private Boolean shouldMentionReferencedAuthor(Message message) {
|
||||
if(message.getReferencedMessage() != null) {
|
||||
return message.getMentionedUsers().contains(message.getReferencedMessage().getAuthor());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>link-embed</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -19,5 +19,7 @@ public class MessageEmbeddedModel extends UserInitiatedServerContext {
|
||||
private TextChannel sourceChannel;
|
||||
private Member embeddingUser;
|
||||
private ButtonConfigModel buttonConfigModel;
|
||||
private Long referencedMessageId;
|
||||
private Boolean mentionsReferencedMessage;
|
||||
private Boolean useButton;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>logging</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi
|
||||
import dev.sheldan.abstracto.core.utils.ContextUtils;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.logging.config.LoggingFeatureDefinition;
|
||||
import dev.sheldan.abstracto.logging.config.LoggingPostTarget;
|
||||
import dev.sheldan.abstracto.logging.model.template.MessageDeletedAttachmentLog;
|
||||
@@ -81,11 +82,14 @@ public class MessageDeleteLogListener implements AsyncMessageDeletedListener {
|
||||
.member(authorMember)
|
||||
.build();
|
||||
MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_DELETED_TEMPLATE, logModel, messageFromCache.getServerId());
|
||||
postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId());
|
||||
FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId())).exceptionally(throwable -> {
|
||||
log.error("Failed to send message deleted log.", throwable);
|
||||
return null;
|
||||
});
|
||||
if(messageFromCache.getAttachments() != null){
|
||||
log.debug("Notifying about deletions of {} attachments.", messageFromCache.getAttachments().size());
|
||||
for (int i = 0; i < messageFromCache.getAttachments().size(); i++) {
|
||||
MessageDeletedAttachmentLog log = MessageDeletedAttachmentLog
|
||||
MessageDeletedAttachmentLog attachmentLogModel = MessageDeletedAttachmentLog
|
||||
.builder()
|
||||
.imageUrl(messageFromCache.getAttachments().get(i).getProxyUrl())
|
||||
.counter(i + 1)
|
||||
@@ -93,8 +97,12 @@ public class MessageDeleteLogListener implements AsyncMessageDeletedListener {
|
||||
.channel(textChannel)
|
||||
.member(authorMember)
|
||||
.build();
|
||||
MessageToSend attachmentEmbed = templateService.renderEmbedTemplate(MESSAGE_DELETED_ATTACHMENT_TEMPLATE, log, messageFromCache.getServerId());
|
||||
postTargetService.sendEmbedInPostTarget(attachmentEmbed, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId());
|
||||
MessageToSend attachmentEmbed = templateService.renderEmbedTemplate(MESSAGE_DELETED_ATTACHMENT_TEMPLATE, attachmentLogModel, messageFromCache.getServerId());
|
||||
FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(attachmentEmbed, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId()))
|
||||
.exceptionally(throwable -> {
|
||||
log.error("Failed to send message deleted log.", throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>logging</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -48,12 +48,11 @@ public class WarnEntryConverter {
|
||||
allFutures.add(warnedMemberFuture);
|
||||
});
|
||||
CompletableFuture<List<WarnEntry>> future = new CompletableFuture<>();
|
||||
FutureUtils.toSingleFutureGeneric(allFutures).whenComplete((unused, throwable) -> {
|
||||
try {
|
||||
future.complete(self.loadFullWarnEntries(loadedWarnings));
|
||||
} catch (Exception exception) {
|
||||
future.completeExceptionally(exception);
|
||||
}
|
||||
FutureUtils.toSingleFutureGeneric(allFutures)
|
||||
.whenComplete((unused, throwable) -> future.complete(self.loadFullWarnEntries(loadedWarnings)))
|
||||
.exceptionally(throwable -> {
|
||||
future.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
@@ -90,6 +90,9 @@ public class BanServiceBean implements BanService {
|
||||
returningFuture.completeExceptionally(throwable1);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
returningFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
return returningFuture;
|
||||
}
|
||||
|
||||
@@ -163,6 +163,9 @@ public class MuteServiceBean implements MuteService {
|
||||
channelService.sendTextToChannel(throwable.getMessage(), feedBackChannel).whenComplete((exceptionMessage, innerThrowable) -> {
|
||||
notificationFuture.complete(null);
|
||||
log.info("Successfully notified user {} in server {} about mute.", memberBeingMuted.getId(), memberBeingMuted.getGuild().getId());
|
||||
}).exceptionally(throwable1 -> {
|
||||
notificationFuture.completeExceptionally(throwable1);
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -155,14 +155,18 @@ public class PurgeServiceBean implements PurgeService {
|
||||
return aVoid -> {
|
||||
if (amountToDelete >= 1) {
|
||||
log.debug("Still more than 1 message to delete. Continuing.");
|
||||
purgeMessages(amountToDelete, channel, earliestMessage.getIdLong(), purgedMember, totalCount, currentCount, currentStatusMessageId).whenComplete((avoid, throwable) -> {
|
||||
purgeMessages(amountToDelete, channel, earliestMessage.getIdLong(), purgedMember, totalCount, currentCount, currentStatusMessageId)
|
||||
.whenComplete((avoid, throwable) -> {
|
||||
if (throwable != null) {
|
||||
deletionFuture.completeExceptionally(throwable);
|
||||
} else {
|
||||
deletionFuture.complete(null);
|
||||
}
|
||||
}
|
||||
);
|
||||
).exceptionally(throwable -> {
|
||||
deletionFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
log.debug("Completed purging of {} messages.", totalCount);
|
||||
// Todo Move to message service
|
||||
|
||||
@@ -188,16 +188,20 @@ public class WarnServiceBean implements WarnService {
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(WARN_DECAY_NOTIFICATION_TEMPLATE_KEY, model, serverId);
|
||||
log.info("Notifying user {} in server {} about decayed warning {}.", userId, serverId, warningId);
|
||||
notificationFutures.add(messageService.sendMessageToSendToUser(memberToSendTo.getUser(), messageToSend).exceptionally(throwable -> {
|
||||
log.error("Failed to send warn decay message to user {} in server {} to notify about decay warning {}.", userId, server, warningId);
|
||||
log.error("Failed to send warn decay message to user {} in server {} to notify about decay warning {}.", userId, server.getId(), warningId, throwable);
|
||||
return null;
|
||||
}));
|
||||
} else {
|
||||
log.warn("Could not find user {} in server {}. Not notifying about decayed warning {}.", userId, serverId, warningId);
|
||||
}
|
||||
});
|
||||
CompletableFuture<Void> future = new CompletableFuture();
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
FutureUtils.toSingleFutureGeneric(notificationFutures)
|
||||
.whenComplete((unused, throwable) -> future.complete(null));
|
||||
.whenComplete((unused, throwable) -> future.complete(null))
|
||||
.exceptionally(throwable -> {
|
||||
future.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>modmail</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -57,7 +57,10 @@ public class ModMailMessageDeletedListener implements AsyncMessageDeletedListene
|
||||
}
|
||||
CompletableFuture.allOf(dmDeletePromise, channelDeletePromise).whenComplete((unused, throwable) ->
|
||||
self.removeMessageFromThread(message.getMessageId())
|
||||
);
|
||||
).exceptionally(throwable -> {
|
||||
log.error("Failed to delete message.", throwable);
|
||||
return null;
|
||||
});
|
||||
});
|
||||
});
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
|
||||
@@ -101,7 +101,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
|
||||
}
|
||||
List<Message> loadedMessages = new ArrayList<>();
|
||||
CompletableFuture.allOf(threadHistoryFuture, privateHistoryFuture)
|
||||
.thenCompose(unused -> loadMoreMessages(messageIdsToLoad, privateHistoryFuture.join(), modMailThread, threadHistoryFuture.join(), privateChannel, loadedMessages, 0))
|
||||
.thenCompose(unused -> loadMoreMessages(messageIdsToLoad.size(), messageIdsToLoad, privateHistoryFuture.join(), modMailThread, threadHistoryFuture.join(), privateChannel, loadedMessages, 0))
|
||||
.thenAccept(unused -> {
|
||||
Set<Long> userIds = messageIds
|
||||
.stream()
|
||||
@@ -124,10 +124,11 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
|
||||
return future;
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> loadMoreMessages(List<Long> messagesToLoad,
|
||||
public CompletableFuture<Void> loadMoreMessages(Integer totalMessageCount, List<Long> messagesToLoad,
|
||||
MessageHistory privateMessageHistory, TextChannel thread,
|
||||
MessageHistory threadMessageHistory, PrivateChannel dmChannel, List<Message> loadedMessages, Integer counter) {
|
||||
if(counter == messagesToLoad.size()) {
|
||||
// TODO maybe find a better mechanism for this... one which does not lead to infinite loops, but also doesnt miss out on history
|
||||
if(counter.equals(totalMessageCount * 2)) {
|
||||
log.warn("We encountered the maximum of {} iterations when loading modmail history - aborting.", messagesToLoad.size());
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
@@ -171,7 +172,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
|
||||
privateHistoryAction = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
return CompletableFuture.allOf(threadHistoryAction, privateHistoryAction)
|
||||
.thenCompose(lists -> loadMoreMessages(messagesToLoad, threadHistoryAction.join(), thread, privateHistoryAction.join(), dmChannel, loadedMessages, counter + 1));
|
||||
.thenCompose(lists -> loadMoreMessages(totalMessageCount, messagesToLoad, threadHistoryAction.join(), thread, privateHistoryAction.join(), dmChannel, loadedMessages, counter + 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -233,10 +233,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
CompletableFuture<Void> headerFuture = sendModMailHeader(channel, member);
|
||||
CompletableFuture<Message> userReplyMessage;
|
||||
if(initialMessage != null){
|
||||
log.debug("Sending initial message {} of user {} to modmail thread {}.", initialMessage.getId(), member.getId(), channel.getId());
|
||||
log.info("Sending initial message {} of user {} to modmail thread {}.", initialMessage.getId(), member.getId(), channel.getId());
|
||||
userReplyMessage = self.sendUserReply(channel, 0L, initialMessage, member, false);
|
||||
} else {
|
||||
log.debug("No initial message to send.");
|
||||
log.info("No initial message to send.");
|
||||
userReplyMessage = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
CompletableFuture notificationFuture;
|
||||
@@ -349,6 +349,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
log.info("There were {} shared servers found which have modmail enabled.", availableGuilds.size());
|
||||
// if more than 1 server is available, show a choice dialog
|
||||
ArrayList<UndoActionInstance> undoActions = new ArrayList<>();
|
||||
if(availableGuilds.size() > 1) {
|
||||
ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel
|
||||
.builder()
|
||||
@@ -365,15 +366,16 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
log.debug("Executing action for creationg a modmail thread in server {} for user {}.", chosenServerId, userId);
|
||||
memberService.getMemberInServerAsync(chosenServerId, userId).thenCompose(member -> {
|
||||
try {
|
||||
return self.createModMailThreadForUser(member, initialMessage, initialMessage.getChannel(), true, new ArrayList<>());
|
||||
return self.createModMailThreadForUser(member, initialMessage, initialMessage.getChannel(), true, undoActions);
|
||||
} catch (Exception exception) {
|
||||
log.error("Setting up modmail thread for user {} in server {} failed.", userId, chosenServerId, exception);
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
future.completeExceptionally(exception);
|
||||
return future;
|
||||
}
|
||||
}).exceptionally(throwable -> {
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to load member {} for modmail in server {}.", userId, chosenServerId, throwable);
|
||||
undoActionService.performActions(undoActions);
|
||||
return null;
|
||||
});
|
||||
})
|
||||
@@ -386,7 +388,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
log.info("Only one server available to modmail. Directly opening modmail thread for user {} in server {}.", initialMessage.getAuthor().getId(), chosenServerId);
|
||||
memberService.getMemberInServerAsync(chosenServerId, initialMessage.getAuthor().getIdLong()).thenCompose(member -> {
|
||||
try {
|
||||
return self.createModMailThreadForUser(member, initialMessage, initialMessage.getChannel(), true, new ArrayList<>());
|
||||
return self.createModMailThreadForUser(member, initialMessage, initialMessage.getChannel(), true, undoActions);
|
||||
} catch (Exception exception) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
future.completeExceptionally(exception);
|
||||
@@ -394,6 +396,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to setup thread correctly", throwable);
|
||||
undoActionService.performActions(undoActions);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
@@ -479,9 +482,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
if(subscriberList.isEmpty()) {
|
||||
subscriberMemberFutures.add(CompletableFuture.completedFuture(null));
|
||||
}
|
||||
log.debug("Mentioning {} subscribers for modmail thread {}.", subscriberList.size(), modMailThreadId);
|
||||
log.info("Mentioning {} subscribers for modmail thread {}.", subscriberList.size(), modMailThreadId);
|
||||
} else {
|
||||
subscriberMemberFutures.add(CompletableFuture.completedFuture(null));
|
||||
log.info("Initial setup of modmail - not mentioning subscribers.");
|
||||
}
|
||||
CompletableFuture<Message> messageFuture = new CompletableFuture<>();
|
||||
FutureUtils.toSingleFutureGeneric(subscriberMemberFutures).whenComplete((unused, throwable) -> {
|
||||
@@ -518,6 +522,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
messageFuture.completeExceptionally(throwable1);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
messageFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
return messageFuture;
|
||||
|
||||
@@ -548,7 +555,6 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
@Transactional
|
||||
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions, Member targetMember) {
|
||||
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", replyCommandMessage.getId(), targetMember.getId(), modmailThreadId, targetMember.getGuild().getId());
|
||||
AUserInAServer moderator = userInServerManagementService.loadOrCreateUser(replyCommandMessage.getMember());
|
||||
metricService.incrementCounter(MDOMAIL_THREAD_MESSAGE_SENT);
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getById(modmailThreadId);
|
||||
FullUserInServer fullThreadUser = FullUserInServer
|
||||
@@ -567,9 +573,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
log.debug("Message is sent anonymous.");
|
||||
modMailModeratorReplyModelBuilder.moderator(memberService.getBotInGuild(modMailThread.getServer()));
|
||||
} else {
|
||||
// should be loaded, because we are currently processing a command caused by the message
|
||||
Member moderatorMember = memberService.getMemberInServer(moderator);
|
||||
modMailModeratorReplyModelBuilder.moderator(moderatorMember);
|
||||
modMailModeratorReplyModelBuilder.moderator(replyCommandMessage.getMember());
|
||||
}
|
||||
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY, modMailUserReplyModel, modMailThread.getServer().getId());
|
||||
@@ -581,7 +585,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
sameThreadMessageFuture = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
return CompletableFuture.allOf(future, sameThreadMessageFuture).thenAccept(avoid ->
|
||||
self.saveSendMessagesAndUpdateState(modmailThreadId, anonymous, moderator, future.join(), replyCommandMessage, sameThreadMessageFuture.join())
|
||||
self.saveSendMessagesAndUpdateState(modmailThreadId, anonymous, future.join(), replyCommandMessage, sameThreadMessageFuture.join())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -815,11 +819,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
.builder()
|
||||
.closingMember(closingContext.getClosingMember())
|
||||
.note(closingContext.getNote())
|
||||
.silently(closingContext.getNotifyUser())
|
||||
.silently(!closingContext.getNotifyUser())
|
||||
.messageCount(modMailThread.getMessages().size())
|
||||
.startDate(modMailThread.getCreated())
|
||||
.serverId(modMailThread.getServer().getId())
|
||||
.silently(!closingContext.getNotifyUser())
|
||||
.userId(modMailThread.getUser().getUserReference().getId())
|
||||
.build();
|
||||
return userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenApply(user -> {
|
||||
@@ -886,15 +889,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* and updates the state of the {@link ModMailThread}.
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} for which the messages were sent for
|
||||
* @param anonymous Whether or not the messages were send anonymous
|
||||
* @param moderator The original {@link AUserInAServer} which authored the messages
|
||||
* @param createdMessageInDM The {@link Message message} which was sent to the private channel with the {@link User user}
|
||||
* @param modMailThreadMessage The {@link Message message} which was sent in the channel representing the {@link ModMailThread thread}. Might be null.
|
||||
* @param replyCommandMessage The {@link Message message} which contained the command used to reply to the user
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
*/
|
||||
@Transactional
|
||||
public void saveSendMessagesAndUpdateState(Long modMailThreadId, Boolean anonymous, AUserInAServer moderator, Message createdMessageInDM, Message replyCommandMessage, Message modMailThreadMessage) {
|
||||
public void saveSendMessagesAndUpdateState(Long modMailThreadId, Boolean anonymous, Message createdMessageInDM, Message replyCommandMessage, Message modMailThreadMessage) {
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getByIdOptional(modMailThreadId);
|
||||
AUserInAServer moderator = userInServerManagementService.loadOrCreateUser(replyCommandMessage.getMember());
|
||||
if(modMailThreadOpt.isPresent()) {
|
||||
ModMailThread modMailThread = modMailThreadOpt.get();
|
||||
log.debug("Adding (anonymous: {}) message {} of moderator to modmail thread {} and setting state to {}.", anonymous, createdMessageInDM.getId(), modMailThreadId, ModMailThreadState.MOD_REPLIED);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>modmail</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto</groupId>
|
||||
<artifactId>abstracto-application</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>profanity-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>profanity-filter</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>remind</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>remind</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>repost-detection</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>repost-detection</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>starboard</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -7,9 +7,11 @@ 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.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
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.starboard.config.StarboardFeatureConfig;
|
||||
import dev.sheldan.abstracto.starboard.model.database.StarboardPost;
|
||||
import dev.sheldan.abstracto.starboard.service.StarboardService;
|
||||
import dev.sheldan.abstracto.starboard.service.management.StarboardPostManagementService;
|
||||
@@ -19,6 +21,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -52,6 +56,9 @@ public abstract class StarboardListener {
|
||||
@Autowired
|
||||
protected MetricService metricService;
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
public static final String STARBOARD_STARS = "starboard.stars";
|
||||
public static final String STARBOARD_POSTS = "starboard.posts";
|
||||
public static final String STAR_ACTION = "action";
|
||||
@@ -69,6 +76,11 @@ public abstract class StarboardListener {
|
||||
.build();
|
||||
|
||||
protected void handleStarboardPostChange(CachedMessage message, CachedReactions reaction, ServerUser userReacting, boolean adding) {
|
||||
Long starMaxDays = configService.getLongValueOrConfigDefault(StarboardFeatureConfig.STAR_MAX_DAYS_CONFIG_KEY, message.getServerId());
|
||||
if(message.getTimeCreated().isBefore(Instant.now().minus(starMaxDays, ChronoUnit.DAYS))) {
|
||||
log.info("Post {} in channel {} in guild {} is beyond the configured max day amount of {} - ignoring.", message.getMessageId(), message.getChannelId(), message.getServerId(), starMaxDays);
|
||||
return;
|
||||
}
|
||||
Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId());
|
||||
boolean starboardPostExists = starboardPostOptional.isPresent();
|
||||
if(starboardPostExists && starboardPostOptional.get().isIgnored()) {
|
||||
|
||||
@@ -13,6 +13,9 @@ abstracto.systemConfigs.starLvl4.longValue=17
|
||||
abstracto.systemConfigs.starLvls.name=starLvls
|
||||
abstracto.systemConfigs.starLvls.longValue=4
|
||||
|
||||
abstracto.systemConfigs.starMaxDays.name=starMaxDays
|
||||
abstracto.systemConfigs.starMaxDays.longValue=7
|
||||
|
||||
abstracto.featureFlags.starboard.featureName=starboard
|
||||
abstracto.featureFlags.starboard.enabled=false
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedReactions;
|
||||
import dev.sheldan.abstracto.core.models.database.*;
|
||||
import dev.sheldan.abstracto.core.models.listener.ReactionAddedModel;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
||||
import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
@@ -26,6 +27,7 @@ import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -53,6 +55,9 @@ public class StarAddedListenerTest {
|
||||
@Mock
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Mock
|
||||
private ConfigService configService;
|
||||
|
||||
@Mock
|
||||
private EmoteService emoteService;
|
||||
|
||||
@@ -117,6 +122,8 @@ public class StarAddedListenerTest {
|
||||
when(member.getUser()).thenReturn(user);
|
||||
when(model.getMemberReacting()).thenReturn(member);
|
||||
when(user.isBot()).thenReturn(false);
|
||||
when(configService.getLongValueOrConfigDefault(StarboardFeatureConfig.STAR_MAX_DAYS_CONFIG_KEY, SERVER_ID)).thenReturn(1L);
|
||||
when(cachedMessage.getTimeCreated()).thenReturn(Instant.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -7,6 +7,7 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedReactions;
|
||||
import dev.sheldan.abstracto.core.models.database.*;
|
||||
import dev.sheldan.abstracto.core.models.listener.ReactionRemovedModel;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
||||
import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
@@ -16,13 +17,16 @@ import dev.sheldan.abstracto.starboard.service.StarboardService;
|
||||
import dev.sheldan.abstracto.starboard.service.management.StarboardPostManagementService;
|
||||
import dev.sheldan.abstracto.starboard.service.management.StarboardPostReactorManagementService;
|
||||
import net.dv8tion.jda.api.entities.MessageReaction;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -51,6 +55,9 @@ public class StarRemovedListenerTest {
|
||||
@Mock
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Mock
|
||||
private ConfigService configService;
|
||||
|
||||
@Mock
|
||||
private EmoteService emoteService;
|
||||
|
||||
@@ -104,6 +111,12 @@ public class StarRemovedListenerTest {
|
||||
private static final Long AUTHOR_ID = 4L;
|
||||
private static final Long USER_ACTING_ID = 7L;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(configService.getLongValueOrConfigDefault(StarboardFeatureConfig.STAR_MAX_DAYS_CONFIG_KEY, SERVER_ID)).thenReturn(1L);
|
||||
when(cachedMessage.getTimeCreated()).thenReturn(Instant.now());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthorRemovingReaction() {
|
||||
when(cachedAuthor.getAuthorId()).thenReturn(AUTHOR_ID);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>starboard</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ public class StarboardFeatureConfig implements FeatureConfig {
|
||||
public static final String STAR_BADGE_EMOTE_PREFIX = "starboardBadge";
|
||||
public static final String STAR_LEVELS_CONFIG_KEY = "starLvls";
|
||||
public static final String STAR_EMOTE = "star";
|
||||
public static final String STAR_MAX_DAYS_CONFIG_KEY = "starMaxDays";
|
||||
|
||||
@Autowired
|
||||
private DefaultConfigManagementService defaultConfigManagementService;
|
||||
@@ -40,6 +41,7 @@ public class StarboardFeatureConfig implements FeatureConfig {
|
||||
for(int i = maxLevels; i > 0; i--) {
|
||||
configKeys.add(StarboardFeatureConfig.STAR_LVL_CONFIG_PREFIX + i);
|
||||
}
|
||||
configKeys.add(STAR_MAX_DAYS_CONFIG_KEY);
|
||||
return configKeys;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>statistic</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>statistic</artifactId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ public class TrackedEmote implements Serializable, Fakeable {
|
||||
@EmbeddedId
|
||||
private ServerSpecificId trackedEmoteId;
|
||||
|
||||
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
|
||||
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
|
||||
@MapsId("serverId")
|
||||
@JoinColumn(name = "server_id", referencedColumnName = "id", nullable = false)
|
||||
private AServer server;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>suggestion</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package dev.sheldan.abstracto.suggestion.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
|
||||
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.ParameterValidator;
|
||||
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.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionInfoModel;
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionService;
|
||||
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;
|
||||
|
||||
@Component
|
||||
public class ShowSuggestion extends AbstractConditionableCommand {
|
||||
|
||||
public static final String SHOW_SUGGESTION_TEMPLATE_KEY = "suggestion_info_response";
|
||||
|
||||
@Autowired
|
||||
private SuggestionService suggestionService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Long suggestionId = (Long) parameters.get(0);
|
||||
|
||||
SuggestionInfoModel suggestionInfoModel = suggestionService.getSuggestionInfo(commandContext.getGuild().getIdLong(), suggestionId);
|
||||
return FutureUtils.toSingleFutureGeneric(
|
||||
channelService.sendEmbedTemplateInTextChannelList(SHOW_SUGGESTION_TEMPLATE_KEY, suggestionInfoModel, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
|
||||
List<ParameterValidator> suggestionIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L));
|
||||
parameters.add(Parameter.builder().name("suggestionId").validators(suggestionIdValidator).type(Long.class).templated(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(false).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("showSuggestion")
|
||||
.module(UtilityModuleDefinition.UTILITY)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SuggestionFeatureDefinition.SUGGEST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package dev.sheldan.abstracto.suggestion.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.ListenerPriority;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.listener.ButtonClickedListenerResult;
|
||||
import dev.sheldan.abstracto.core.listener.async.jda.ButtonClickedListener;
|
||||
import dev.sheldan.abstracto.core.models.listener.ButtonClickedListenerModel;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionButtonPayload;
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionServiceBean;
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionVoteService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
|
||||
import net.dv8tion.jda.api.interactions.components.ButtonInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SuggestionButtonVoteClickedListener implements ButtonClickedListener {
|
||||
|
||||
@Autowired
|
||||
private SuggestionVoteService suggestionVoteService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
public static final String VOTE_REMOVED_TEMPLATE_KEY = "suggestion_vote_removed_notification";
|
||||
public static final String VOTE_CAST_TEMPLATE_KEY = "suggestion_vote_cast_notification";
|
||||
|
||||
@Override
|
||||
public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) {
|
||||
ButtonClickEvent event = model.getEvent();
|
||||
SuggestionButtonPayload payload = (SuggestionButtonPayload) model.getDeserializedPayload();
|
||||
suggestionVoteService.upsertSuggestionVote(event.getMember(), payload.getDecision(), payload.getSuggestionId());
|
||||
ButtonInteraction buttonInteraction = model.getEvent().getInteraction();
|
||||
String templateToUse;
|
||||
switch (payload.getDecision()) {
|
||||
case AGREE:
|
||||
case DISAGREE:
|
||||
templateToUse = VOTE_CAST_TEMPLATE_KEY;
|
||||
break;
|
||||
default:
|
||||
case REMOVE_VOTE:
|
||||
templateToUse = VOTE_REMOVED_TEMPLATE_KEY;
|
||||
}
|
||||
FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(templateToUse, new Object(), buttonInteraction.getHook()))
|
||||
.thenAccept(unused -> log.info("Notified user {} about vote action in suggestion {} in server {}.",
|
||||
model.getEvent().getMember().getIdLong(), payload.getSuggestionId(), payload.getServerId()));
|
||||
|
||||
return ButtonClickedListenerResult.ACKNOWLEDGED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean handlesEvent(ButtonClickedListenerModel model) {
|
||||
return model.getOrigin().equals(SuggestionServiceBean.SUGGESTION_VOTE_ORIGIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SuggestionFeatureDefinition.SUGGEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPriority() {
|
||||
return ListenerPriority.MEDIUM;
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,12 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
@Repository
|
||||
public interface SuggestionRepository extends JpaRepository<Suggestion, ServerSpecificId> {
|
||||
List<Suggestion> findByUpdatedLessThanAndStateNot(Instant start, SuggestionState state);
|
||||
|
||||
Optional<Suggestion> findByMessageId(Long messageId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package dev.sheldan.abstracto.suggestion.repository;
|
||||
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionDecision;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionVote;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.embed.SuggestionVoterId;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface SuggestionVoteRepository extends JpaRepository<SuggestionVote, SuggestionVoterId> {
|
||||
Long countByDecisionAndSuggestionVoteId_SuggestionIdAndSuggestionVoteId_ServerId(SuggestionDecision decision, Long suggestionId, Long serverId);
|
||||
void deleteBySuggestionVoteId_SuggestionIdAndSuggestionVoteId_ServerId(Long suggestionId, Long serverId);
|
||||
}
|
||||
@@ -5,7 +5,9 @@ import dev.sheldan.abstracto.core.models.ServerSpecificId;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.template.button.ButtonConfigModel;
|
||||
import dev.sheldan.abstracto.core.service.*;
|
||||
import dev.sheldan.abstracto.core.service.management.ComponentPayloadManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
@@ -18,10 +20,11 @@ import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureMode;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionPostTarget;
|
||||
import dev.sheldan.abstracto.suggestion.exception.UnSuggestNotPossibleException;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionDecision;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionReminderModel;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.*;
|
||||
import dev.sheldan.abstracto.suggestion.service.management.SuggestionManagementService;
|
||||
import dev.sheldan.abstracto.suggestion.service.management.SuggestionVoteManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -47,6 +50,7 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
public static final String SUGGESTION_NO_EMOTE = "suggestionNo";
|
||||
public static final String SUGGESTION_COUNTER_KEY = "suggestion";
|
||||
public static final String SUGGESTION_REMINDER_TEMPLATE_KEY = "suggest_suggestion_reminder";
|
||||
public static final String SUGGESTION_VOTE_ORIGIN = "suggestionVote";
|
||||
|
||||
@Autowired
|
||||
private SuggestionManagementService suggestionManagementService;
|
||||
@@ -93,6 +97,15 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private ComponentService componentService;
|
||||
|
||||
@Autowired
|
||||
private ComponentPayloadManagementService componentPayloadManagementService;
|
||||
|
||||
@Autowired
|
||||
private SuggestionVoteManagementService suggestionVoteManagementService;
|
||||
|
||||
@Value("${abstracto.feature.suggestion.removalMaxAge}")
|
||||
private Long removalMaxAgeSeconds;
|
||||
|
||||
@@ -106,6 +119,7 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
AUserInAServer userSuggester = userInServerManagementService.loadOrCreateUser(suggester);
|
||||
Long newSuggestionId = counterService.getNextCounterValue(server, SUGGESTION_COUNTER_KEY);
|
||||
Boolean useButtons = featureModeService.featureModeActive(SuggestionFeatureDefinition.SUGGEST, serverId, SuggestionFeatureMode.SUGGESTION_BUTTONS);
|
||||
SuggestionLog model = SuggestionLog
|
||||
.builder()
|
||||
.suggestionId(newSuggestionId)
|
||||
@@ -114,14 +128,35 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
.message(commandMessage)
|
||||
.member(commandMessage.getMember())
|
||||
.suggesterUser(userSuggester)
|
||||
.useButtons(useButtons)
|
||||
.suggester(suggester.getUser())
|
||||
.text(text)
|
||||
.build();
|
||||
if(useButtons) {
|
||||
setupButtonIds(model);
|
||||
}
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_CREATION_TEMPLATE, model, serverId);
|
||||
log.info("Creating suggestion with id {} in server {} from member {}.", newSuggestionId, serverId, suggester.getIdLong());
|
||||
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, serverId);
|
||||
return FutureUtils.toSingleFutureGeneric(completableFutures).thenCompose(aVoid -> {
|
||||
Message message = completableFutures.get(0).join();
|
||||
return FutureUtils.toSingleFutureGeneric(completableFutures)
|
||||
.thenCompose(aVoid -> self.addDeletionPossibility(commandMessage, text, suggester, serverId, newSuggestionId, completableFutures, model));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> addDeletionPossibility(Message commandMessage, String text, Member suggester, Long serverId,
|
||||
Long newSuggestionId, List<CompletableFuture<Message>> completableFutures, SuggestionLog model) {
|
||||
Message message = completableFutures.get(0).join();
|
||||
if(model.getUseButtons()) {
|
||||
configureDecisionButtonPayload(serverId, newSuggestionId, model.getAgreeButtonModel(), SuggestionDecision.AGREE);
|
||||
configureDecisionButtonPayload(serverId, newSuggestionId, model.getDisAgreeButtonModel(), SuggestionDecision.DISAGREE);
|
||||
configureDecisionButtonPayload(serverId, newSuggestionId, model.getRemoveVoteButtonModel(), SuggestionDecision.REMOVE_VOTE);
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
componentPayloadManagementService.createPayload(model.getAgreeButtonModel(), server);
|
||||
componentPayloadManagementService.createPayload(model.getDisAgreeButtonModel(), server);
|
||||
componentPayloadManagementService.createPayload(model.getRemoveVoteButtonModel(), server);
|
||||
self.persistSuggestionInDatabase(suggester, text, message, newSuggestionId, commandMessage);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} else {
|
||||
log.debug("Posted message, adding reaction for suggestion {} to message {}.", newSuggestionId, message.getId());
|
||||
CompletableFuture<Void> firstReaction = reactionService.addReactionToMessageAsync(SUGGESTION_YES_EMOTE, serverId, message);
|
||||
CompletableFuture<Void> secondReaction = reactionService.addReactionToMessageAsync(SUGGESTION_NO_EMOTE, serverId, message);
|
||||
@@ -129,7 +164,25 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
log.debug("Reaction added to message {} for suggestion {}.", message.getId(), newSuggestionId);
|
||||
self.persistSuggestionInDatabase(suggester, text, message, newSuggestionId, commandMessage);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void configureDecisionButtonPayload(Long serverId, Long newSuggestionId, ButtonConfigModel model, SuggestionDecision decision) {
|
||||
SuggestionButtonPayload agreePayload = SuggestionButtonPayload
|
||||
.builder()
|
||||
.suggestionId(newSuggestionId)
|
||||
.serverId(serverId)
|
||||
.decision(decision)
|
||||
.build();
|
||||
model.setButtonPayload(agreePayload);
|
||||
model.setOrigin(SUGGESTION_VOTE_ORIGIN);
|
||||
model.setPayloadType(SuggestionButtonPayload.class);
|
||||
}
|
||||
|
||||
private void setupButtonIds(SuggestionLog suggestionLog) {
|
||||
suggestionLog.setAgreeButtonModel(componentService.createButtonConfigModel());
|
||||
suggestionLog.setDisAgreeButtonModel(componentService.createButtonConfigModel());
|
||||
suggestionLog.setRemoveVoteButtonModel(componentService.createButtonConfigModel());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -179,26 +232,32 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
Long serverId = suggestion.getServer().getId();
|
||||
Long channelId = suggestion.getChannel().getId();
|
||||
Long originalMessageId = suggestion.getMessageId();
|
||||
SuggestionLog model = SuggestionLog
|
||||
Long agreements = suggestionVoteManagementService.getDecisionsForSuggestion(suggestion, SuggestionDecision.AGREE);
|
||||
Long disagreements = suggestionVoteManagementService.getDecisionsForSuggestion(suggestion, SuggestionDecision.DISAGREE);
|
||||
Long suggestionId = suggestion.getSuggestionId().getId();
|
||||
SuggestionUpdateModel model = SuggestionUpdateModel
|
||||
.builder()
|
||||
.suggestionId(suggestion.getSuggestionId().getId())
|
||||
.suggestionId(suggestionId)
|
||||
.state(suggestion.getState())
|
||||
.suggesterUser(suggestion.getSuggester())
|
||||
.serverId(serverId)
|
||||
.member(memberExecutingCommand)
|
||||
.agreeVotes(agreements)
|
||||
.disAgreeVotes(disagreements)
|
||||
.originalMessageId(originalMessageId)
|
||||
.text(suggestion.getSuggestionText())
|
||||
.originalChannelId(channelId)
|
||||
.reason(reason)
|
||||
.build();
|
||||
log.info("Updated posted suggestion {} in server {}.", suggestion.getSuggestionId().getId(), suggestion.getServer().getId());
|
||||
log.info("Updated posted suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
|
||||
CompletableFuture<User> memberById = userService.retrieveUserForId(suggestion.getSuggester().getUserReference().getId());
|
||||
CompletableFuture<Void> finalFuture = new CompletableFuture<>();
|
||||
memberById.whenComplete((user, throwable) -> {
|
||||
if(throwable == null) {
|
||||
model.setSuggester(user);
|
||||
}
|
||||
self.updateSuggestionMessageText(reason, model).thenAccept(unused -> finalFuture.complete(null)).exceptionally(throwable1 -> {
|
||||
self.updateSuggestionMessageText(reason, model).thenAccept(unused -> finalFuture.complete(null))
|
||||
.thenAccept(unused -> self.removeSuggestionButtons(serverId, channelId, originalMessageId, suggestionId))
|
||||
.exceptionally(throwable1 -> {
|
||||
finalFuture.completeExceptionally(throwable1);
|
||||
return null;
|
||||
});
|
||||
@@ -208,11 +267,23 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
});
|
||||
|
||||
return finalFuture;
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> updateSuggestionMessageText(String text, SuggestionLog suggestionLog) {
|
||||
public CompletableFuture<Void> removeSuggestionButtons(Long serverId, Long channelId, Long messageId, Long suggestionId) {
|
||||
Boolean useButtons = featureModeService.featureModeActive(SuggestionFeatureDefinition.SUGGEST, serverId, SuggestionFeatureMode.SUGGESTION_BUTTONS);
|
||||
if(useButtons) {
|
||||
return messageService.loadMessage(serverId, channelId, messageId).thenCompose(message -> {
|
||||
log.info("Clearing buttons from suggestion {} in with message {} in channel {} in server {}.", suggestionId, message, channelId, serverId);
|
||||
return componentService.clearButtons(message);
|
||||
});
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> updateSuggestionMessageText(String text, SuggestionUpdateModel suggestionLog) {
|
||||
suggestionLog.setReason(text);
|
||||
Long serverId = suggestionLog.getServerId();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_UPDATE_TEMPLATE, suggestionLog, serverId);
|
||||
@@ -253,8 +324,11 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
Instant pointInTime = Instant.now().minus(Duration.ofDays(autoRemovalMaxDays)).truncatedTo(ChronoUnit.DAYS);
|
||||
List<Suggestion> suggestionsToRemove = suggestionManagementService.getSuggestionsUpdatedBeforeNotNew(pointInTime);
|
||||
log.info("Removing {} suggestions older than {}.", suggestionsToRemove.size(), pointInTime);
|
||||
suggestionsToRemove.forEach(suggestion -> log.info("Deleting suggestion {} in server {}.",
|
||||
suggestion.getSuggestionId().getId(), suggestion.getSuggestionId().getServerId()));
|
||||
suggestionsToRemove.forEach(suggestion -> {
|
||||
suggestionVoteManagementService.deleteSuggestionVotes(suggestion);
|
||||
log.info("Deleting suggestion {} in server {}.",
|
||||
suggestion.getSuggestionId().getId(), suggestion.getSuggestionId().getServerId());
|
||||
});
|
||||
suggestionManagementService.deleteSuggestion(suggestionsToRemove);
|
||||
}
|
||||
|
||||
@@ -298,6 +372,18 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuggestionInfoModel getSuggestionInfo(Long serverId, Long suggestionId) {
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
||||
Long agreements = suggestionVoteManagementService.getDecisionsForSuggestion(suggestion, SuggestionDecision.AGREE);
|
||||
Long disagreements = suggestionVoteManagementService.getDecisionsForSuggestion(suggestion, SuggestionDecision.DISAGREE);
|
||||
return SuggestionInfoModel
|
||||
.builder()
|
||||
.agreements(agreements)
|
||||
.disagreements(disagreements)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteSuggestion(Long suggestionId, Long serverId) {
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package dev.sheldan.abstracto.suggestion.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionDecision;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionVote;
|
||||
import dev.sheldan.abstracto.suggestion.service.management.SuggestionManagementService;
|
||||
import dev.sheldan.abstracto.suggestion.service.management.SuggestionVoteManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SuggestionVoteServiceBean implements SuggestionVoteService {
|
||||
|
||||
@Autowired
|
||||
private SuggestionVoteManagementService suggestionVoteManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private SuggestionManagementService suggestionManagementService;
|
||||
|
||||
@Override
|
||||
public SuggestionVote upsertSuggestionVote(Member votingMember, SuggestionDecision decision, Long suggestionId) {
|
||||
Long serverId = votingMember.getGuild().getIdLong();
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
||||
return upsertSuggestionVote(votingMember, decision, suggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuggestionVote upsertSuggestionVote(Member votingMember, SuggestionDecision decision, Suggestion suggestion) {
|
||||
AUserInAServer votingUser = userInServerManagementService.loadOrCreateUser(votingMember);
|
||||
Optional<SuggestionVote> suggestionVoteOptional = suggestionVoteManagementService.getSuggestionVote(votingUser, suggestion);
|
||||
if(decision.equals(SuggestionDecision.REMOVE_VOTE)) {
|
||||
deleteSuggestionVote(votingMember, suggestion);
|
||||
return null;
|
||||
}
|
||||
if(suggestionVoteOptional.isPresent()) {
|
||||
log.info("Updating suggestion decision of user {} on suggestion {} in server {} to {}.", votingMember.getIdLong(),
|
||||
suggestion.getSuggestionId().getId(), suggestion.getServer().getId(), decision);
|
||||
SuggestionVote updatedVote = suggestionVoteOptional.get();
|
||||
updatedVote.setDecision(decision);
|
||||
return updatedVote;
|
||||
} else {
|
||||
return suggestionVoteManagementService.createSuggestionVote(votingUser, suggestion, decision);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSuggestionVote(Member votingMember, Long suggestionId) {
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(votingMember.getGuild().getIdLong(), suggestionId);
|
||||
deleteSuggestionVote(votingMember, suggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSuggestionVote(Member votingMember, Suggestion suggestion) {
|
||||
AUserInAServer votingUser = userInServerManagementService.loadOrCreateUser(votingMember);
|
||||
log.info("Removing suggestion vote from user {} on suggestion {} in server {}.",
|
||||
votingMember.getIdLong(), suggestion.getSuggestionId().getId(), suggestion.getServer().getId());
|
||||
suggestionVoteManagementService.deleteSuggestionVote(votingUser, suggestion);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -101,4 +101,9 @@ public class SuggestionManagementServiceBean implements SuggestionManagementServ
|
||||
public List<Suggestion> getSuggestionsUpdatedBeforeNotNew(Instant date) {
|
||||
return suggestionRepository.findByUpdatedLessThanAndStateNot(date, SuggestionState.NEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Suggestion> findSuggestionByMessageId(Long messageId) {
|
||||
return suggestionRepository.findByMessageId(messageId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package dev.sheldan.abstracto.suggestion.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionDecision;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionVote;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.embed.SuggestionVoterId;
|
||||
import dev.sheldan.abstracto.suggestion.repository.SuggestionVoteRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SuggestionVoteManagementServiceBean implements SuggestionVoteManagementService {
|
||||
|
||||
@Autowired
|
||||
private SuggestionVoteRepository suggestionVoteRepository;
|
||||
|
||||
@Override
|
||||
public Optional<SuggestionVote> getSuggestionVote(AUserInAServer aUserInAServer, Suggestion suggestion) {
|
||||
SuggestionVoterId suggestionVoteId = SuggestionVoterId
|
||||
.builder()
|
||||
.suggestionId(suggestion.getSuggestionId().getId())
|
||||
.serverId(suggestion.getServer().getId())
|
||||
.voterId(aUserInAServer.getUserInServerId())
|
||||
.build();
|
||||
return suggestionVoteRepository.findById(suggestionVoteId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSuggestionVote(AUserInAServer aUserInAServer, Suggestion suggestion) {
|
||||
Optional<SuggestionVote> voteOptional = getSuggestionVote(aUserInAServer, suggestion);
|
||||
voteOptional.ifPresent(suggestionVote -> suggestionVoteRepository.delete(suggestionVote));
|
||||
|
||||
if(!voteOptional.isPresent()) {
|
||||
log.warn("User {} in server {} did not have a vote for suggestion {}.",
|
||||
aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId(), suggestion.getSuggestionId().getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuggestionVote createSuggestionVote(AUserInAServer aUserInAServer, Suggestion suggestion, SuggestionDecision decision) {
|
||||
SuggestionVoterId suggestionVoteId = SuggestionVoterId
|
||||
.builder()
|
||||
.suggestionId(suggestion.getSuggestionId().getId())
|
||||
.serverId(suggestion.getServer().getId())
|
||||
.voterId(aUserInAServer.getUserInServerId())
|
||||
.build();
|
||||
SuggestionVote vote = SuggestionVote
|
||||
.builder()
|
||||
.suggestionVoteId(suggestionVoteId)
|
||||
.voter(aUserInAServer)
|
||||
.decision(decision)
|
||||
.suggestion(suggestion)
|
||||
.build();
|
||||
log.info("Creating suggestion decision of user {} on suggestion {} in server {} to {}.", aUserInAServer.getUserReference().getId(),
|
||||
suggestion.getSuggestionId().getId(), suggestion.getServer().getId(), decision);
|
||||
return suggestionVoteRepository.save(vote);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getDecisionsForSuggestion(Suggestion suggestion, SuggestionDecision decision) {
|
||||
return suggestionVoteRepository.countByDecisionAndSuggestionVoteId_SuggestionIdAndSuggestionVoteId_ServerId(decision, suggestion.getSuggestionId().getId(), suggestion.getSuggestionId().getServerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSuggestionVotes(Suggestion suggestion) {
|
||||
suggestionVoteRepository.deleteBySuggestionVoteId_SuggestionIdAndSuggestionVoteId_ServerId(suggestion.getSuggestionId().getId(), suggestion.getSuggestionId().getServerId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
|
||||
<property name="suggestionFeature" value="(SELECT id FROM feature WHERE key = 'suggestion')"/>
|
||||
|
||||
<changeSet author="Sheldan" id="suggestionInfo-commands">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="showSuggestion"/>
|
||||
<column name="module_id" valueComputed="${utilityModule}"/>
|
||||
<column name="feature_id" valueComputed="${suggestionFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="command.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="suggestion_vote-table">
|
||||
<createTable tableName="suggestion_vote">
|
||||
<column name="voter_user_in_server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="suggestion_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="decision" type="VARCHAR(255)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
</createTable>
|
||||
<addPrimaryKey columnNames="voter_user_in_server_id, suggestion_id, server_id" tableName="suggestion_vote" constraintName="pk_suggestion_vote" validate="false"/>
|
||||
<addForeignKeyConstraint baseColumnNames="suggestion_id, server_id" baseTableName="suggestion_vote" constraintName="fk_suggestion_vote_suggestion"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="id, server_id" referencedTableName="suggestion" validate="false"/>
|
||||
<addForeignKeyConstraint baseColumnNames="voter_user_in_server_id" baseTableName="suggestion_vote" constraintName="fk_suggestion_vote_voter"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="false"/>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS suggestion_vote_update_trigger ON suggestion_vote;
|
||||
CREATE TRIGGER suggestion_vote_update_trigger BEFORE UPDATE ON suggestion_vote FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS suggestion_vote_insert_trigger ON suggestion_vote;
|
||||
CREATE TRIGGER suggestion_vote_insert_trigger BEFORE INSERT ON suggestion_vote FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
ALTER TABLE suggestion_vote ADD CONSTRAINT check_suggestion_vote_state CHECK (decision IN ('AGREE','DISAGREE'));
|
||||
</sql>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="suggestion_vote.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -9,4 +9,5 @@
|
||||
<include file="1.0-suggestion/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.2.12/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.2.13/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.3.8/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -12,4 +12,8 @@ abstracto.featureModes.suggestionReminder.mode=suggestionReminder
|
||||
abstracto.featureModes.suggestionReminder.enabled=false
|
||||
|
||||
abstracto.systemConfigs.suggestionReminderDays.name=suggestionReminderDays
|
||||
abstracto.systemConfigs.suggestionReminderDays.longValue=7
|
||||
abstracto.systemConfigs.suggestionReminderDays.longValue=7
|
||||
|
||||
abstracto.featureModes.suggestionButton.featureName=suggestion
|
||||
abstracto.featureModes.suggestionButton.mode=suggestionButton
|
||||
abstracto.featureModes.suggestionButton.enabled=true
|
||||
@@ -19,6 +19,7 @@ import dev.sheldan.abstracto.suggestion.exception.SuggestionNotFoundException;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionUpdateModel;
|
||||
import dev.sheldan.abstracto.suggestion.service.management.SuggestionManagementService;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import org.junit.Test;
|
||||
@@ -123,8 +124,6 @@ public class SuggestionServiceBeanTest {
|
||||
when(member.getGuild()).thenReturn(guild);
|
||||
when(member.getIdLong()).thenReturn(SUGGESTER_ID);
|
||||
testUnit.createSuggestionMessage(message, suggestionText);
|
||||
verify(reactionService, times(1)).addReactionToMessageAsync(SuggestionServiceBean.SUGGESTION_YES_EMOTE, SERVER_ID, suggestionMessage);
|
||||
verify(reactionService, times(1)).addReactionToMessageAsync(SuggestionServiceBean.SUGGESTION_NO_EMOTE, SERVER_ID, suggestionMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -139,10 +138,6 @@ public class SuggestionServiceBeanTest {
|
||||
verify(suggestionManagementService, times(1)).createSuggestion(member, text, message, SUGGESTION_ID, commandMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptExistingSuggestion() {
|
||||
executeAcceptWithMember();
|
||||
}
|
||||
|
||||
@Test(expected = SuggestionNotFoundException.class)
|
||||
public void testAcceptNotExistingSuggestion() {
|
||||
@@ -152,21 +147,6 @@ public class SuggestionServiceBeanTest {
|
||||
testUnit.acceptSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateSuggestionMessage() {
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(log.getServerId()).thenReturn(SERVER_ID);
|
||||
MessageToSend updatedMessage = Mockito.mock(MessageToSend.class);
|
||||
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_UPDATE_TEMPLATE), any(SuggestionLog.class), eq(SERVER_ID))).thenReturn(updatedMessage);
|
||||
testUnit.updateSuggestionMessageText(CLOSING_TEXT, log);
|
||||
verify(postTargetService, times(1)).sendEmbedInPostTarget(updatedMessage, SuggestionPostTarget.SUGGESTION, SERVER_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejectExistingSuggestion() {
|
||||
executeRejectWithMember();
|
||||
}
|
||||
|
||||
@Test(expected = SuggestionNotFoundException.class)
|
||||
public void testRejectNotExistingSuggestion() {
|
||||
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenThrow(new SuggestionNotFoundException(SUGGESTION_ID));
|
||||
@@ -175,42 +155,4 @@ public class SuggestionServiceBeanTest {
|
||||
testUnit.rejectSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||
}
|
||||
|
||||
private void executeAcceptWithMember() {
|
||||
Long messageId = 7L;
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
Suggestion suggestionToAccept = setupClosing(messageId);
|
||||
when(message.getGuild()).thenReturn(guild);
|
||||
when(message.getMember()).thenReturn(member);
|
||||
testUnit.acceptSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||
verify(suggestionManagementService, times(1)).setSuggestionState(suggestionToAccept, SuggestionState.ACCEPTED);
|
||||
}
|
||||
|
||||
private void executeRejectWithMember() {
|
||||
Long messageId = 7L;
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
Suggestion suggestionToAccept = setupClosing(messageId);
|
||||
when(message.getGuild()).thenReturn(guild);
|
||||
when(message.getMember()).thenReturn(member);
|
||||
testUnit.rejectSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||
verify(suggestionManagementService, times(1)).setSuggestionState(suggestionToAccept, SuggestionState.REJECTED);
|
||||
}
|
||||
|
||||
private Suggestion setupClosing(Long messageId) {
|
||||
Suggestion suggestionToAccept = Mockito.mock(Suggestion.class);
|
||||
when(suggestionToAccept.getChannel()).thenReturn(channel);
|
||||
when(suggestionToAccept.getServer()).thenReturn(server);
|
||||
when(suggestionToAccept.getSuggester()).thenReturn(suggester);
|
||||
AUser aUser = Mockito.mock(AUser.class);
|
||||
when(aUser.getId()).thenReturn(USER_ID);
|
||||
when(suggester.getUserReference()).thenReturn(aUser);
|
||||
ServerSpecificId suggestionId = Mockito.mock(ServerSpecificId.class);
|
||||
when(suggestionId.getId()).thenReturn(SUGGESTION_ID);
|
||||
when(suggestionToAccept.getSuggestionId()).thenReturn(suggestionId);
|
||||
when(suggestionToAccept.getMessageId()).thenReturn(messageId);
|
||||
when(server.getId()).thenReturn(SERVER_ID);
|
||||
when(channel.getId()).thenReturn(CHANNEL_ID);
|
||||
when(userService.retrieveUserForId(USER_ID)).thenReturn(CompletableFuture.completedFuture(suggesterUser));
|
||||
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenReturn(suggestionToAccept);
|
||||
return suggestionToAccept;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>suggestion</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.6</version>
|
||||
<version>1.3.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ import java.util.List;
|
||||
@Component
|
||||
public class SuggestionFeatureConfig implements FeatureConfig {
|
||||
|
||||
public static final String SUGGESTION_AGREE_EMOTE = "suggestionYes";
|
||||
public static final String SUGGESTION_DISAGREE_EMOTE = "suggestionNo";
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SuggestionFeatureDefinition.SUGGEST;
|
||||
@@ -25,12 +28,12 @@ public class SuggestionFeatureConfig implements FeatureConfig {
|
||||
|
||||
@Override
|
||||
public List<String> getRequiredEmotes() {
|
||||
return Arrays.asList("suggestionYes", "suggestionNo");
|
||||
return Arrays.asList(SUGGESTION_AGREE_EMOTE, SUGGESTION_DISAGREE_EMOTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getAvailableModes() {
|
||||
return Arrays.asList(SuggestionFeatureMode.SUGGESTION_REMINDER);
|
||||
return Arrays.asList(SuggestionFeatureMode.SUGGESTION_REMINDER, SuggestionFeatureMode.SUGGESTION_BUTTONS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,7 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum SuggestionFeatureMode implements FeatureMode {
|
||||
SUGGESTION_REMINDER("suggestionReminder");
|
||||
SUGGESTION_REMINDER("suggestionReminder"), SUGGESTION_BUTTONS("suggestionButton");
|
||||
|
||||
private final String key;
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.database;
|
||||
|
||||
public enum SuggestionDecision {
|
||||
AGREE, DISAGREE, REMOVE_VOTE
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.database;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.embed.SuggestionVoterId;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
@Table(name="suggestion_vote")
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
public class SuggestionVote {
|
||||
|
||||
@Id
|
||||
@EmbeddedId
|
||||
private SuggestionVoterId suggestionVoteId;
|
||||
|
||||
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
|
||||
@MapsId("voterId")
|
||||
@JoinColumn(name = "voter_user_in_server_id", nullable = false)
|
||||
private AUserInAServer voter;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumns(
|
||||
{
|
||||
@JoinColumn(updatable = false, insertable = false, name = "suggestion_id", referencedColumnName = "id"),
|
||||
@JoinColumn(updatable = false, insertable = false, name = "server_id", referencedColumnName = "server_id")
|
||||
})
|
||||
private Suggestion suggestion;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "decision", nullable = false)
|
||||
private SuggestionDecision decision;
|
||||
|
||||
@Column(name = "created", nullable = false, insertable = false, updatable = false)
|
||||
private Instant created;
|
||||
|
||||
@Column(name = "updated", insertable = false, updatable = false)
|
||||
private Instant updated;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.database.embed;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Embeddable
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@EqualsAndHashCode
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SuggestionVoterId implements Serializable {
|
||||
@Column(name = "voter_user_in_server_id")
|
||||
private Long voterId;
|
||||
|
||||
@Column(name = "suggestion_id")
|
||||
private Long suggestionId;
|
||||
|
||||
@Column(name = "server_id")
|
||||
private Long serverId;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.button.ButtonPayload;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionDecision;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class SuggestionButtonPayload implements ButtonPayload {
|
||||
private Long suggestionId;
|
||||
private Long serverId;
|
||||
private SuggestionDecision decision;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.template;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class SuggestionInfoModel {
|
||||
private Long agreements;
|
||||
private Long disagreements;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.template.button.ButtonConfigModel;
|
||||
import dev.sheldan.abstracto.core.utils.MessageUtils;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import lombok.Getter;
|
||||
@@ -25,6 +26,10 @@ public class SuggestionLog {
|
||||
private Long serverId;
|
||||
private Long originalChannelId;
|
||||
private Long originalMessageId;
|
||||
private Boolean useButtons;
|
||||
private ButtonConfigModel agreeButtonModel;
|
||||
private ButtonConfigModel disAgreeButtonModel;
|
||||
private ButtonConfigModel removeVoteButtonModel;
|
||||
|
||||
public String getOriginalMessageUrl() {
|
||||
return MessageUtils.buildMessageUrl(serverId, originalChannelId , originalMessageId);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.utils.MessageUtils;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@SuperBuilder
|
||||
public class SuggestionUpdateModel {
|
||||
private Long suggestionId;
|
||||
private SuggestionState state;
|
||||
private User suggester;
|
||||
private Member member;
|
||||
private String text;
|
||||
private Message message;
|
||||
private String reason;
|
||||
private Long serverId;
|
||||
private Long originalChannelId;
|
||||
private Long originalMessageId;
|
||||
private Long agreeVotes;
|
||||
private Long disAgreeVotes;
|
||||
|
||||
public String getOriginalMessageUrl() {
|
||||
return MessageUtils.buildMessageUrl(serverId, originalChannelId , originalMessageId);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user