mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-02 15:56:34 +00:00
Compare commits
20 Commits
2024050522
...
v1.5.39
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
826bee1f81 | ||
|
|
99bf9a9be0 | ||
|
|
5b5e4973a7 | ||
|
|
65e956827c | ||
|
|
b258a8bc54 | ||
|
|
9864b7d875 | ||
|
|
27466b7333 | ||
|
|
bfb8969d1f | ||
|
|
0097ff801a | ||
|
|
b6a188c04d | ||
|
|
2fa1adde02 | ||
|
|
cb8b64cc01 | ||
|
|
3b3dd0dbb7 | ||
|
|
388fead2a6 | ||
|
|
336c3d0bd8 | ||
|
|
4991ad8f1c | ||
|
|
c5136a1808 | ||
|
|
446d882eec | ||
|
|
b3e207a967 | ||
|
|
5c25345cf8 |
2
.env
2
.env
@@ -1,2 +1,2 @@
|
||||
REGISTRY_PREFIX=harbor.sheldan.dev/abstracto/
|
||||
VERSION=1.5.35
|
||||
VERSION=1.5.38
|
||||
@@ -8,7 +8,6 @@ Abstracto represents a framework to be used as a basis for a Discord bot. It use
|
||||
and provides an extensive tool set to create new commands and a wide range of commands out of the box.
|
||||
|
||||
This repository does not provide the full functionality in order to start a discord bot, because it requires a Main class.
|
||||
An example implementation of this bot can be seen [here](https://github.com/Sheldan/Crimson). This repository contains the required configuration in order to run a bot and example customizations.
|
||||
|
||||
|
||||
## Technologies
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</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.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>experience-tracking</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class AddMemberToChannelLevelAction implements LevelActionListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class AddRoleLevelAction implements LevelActionListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class RemoveMemberFromChannelLevelAction implements LevelActionListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public class RemoveRoleLevelAction implements LevelActionListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction) {
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.exception.InputFormatException;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.MemberService;
|
||||
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.core.utils.ParseUtils;
|
||||
import dev.sheldan.abstracto.experience.model.LevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.SendMessageToChannelLevelActionMessageModel;
|
||||
import dev.sheldan.abstracto.experience.model.SendMessageToChannelLevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SendMessageToChannelLevelAction implements LevelActionListener {
|
||||
|
||||
public static final String ACTION_NAME = "send_message_to_channel_above_level";
|
||||
private static final String LEVEL_ACTION_SEND_MESSAGE_TEMPLATE_KEY = "levelAction_sendMessageToChannel_template";
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ACTION_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container) {
|
||||
SendMessageToChannelLevelActionPayload payload = (SendMessageToChannelLevelActionPayload) levelAction.getLoadedPayload();
|
||||
SendMessageToChannelLevelActionMessageModel.SendMessageToChannelLevelActionMessageModelBuilder messageModelBuilder = SendMessageToChannelLevelActionMessageModel
|
||||
.builder()
|
||||
.level(userExperience.getLevelOrDefault())
|
||||
.templateKey(payload.getTemplateKey())
|
||||
.experience(userExperience.getExperience());
|
||||
ServerUser serverUser = ServerUser.fromAUserInAServer(userExperience.getUser());
|
||||
memberService.getMemberInServerAsync(serverUser).thenAccept(member -> {
|
||||
messageModelBuilder.memberDisplay(MemberDisplay.fromMember(member));
|
||||
SendMessageToChannelLevelActionMessageModel model = messageModelBuilder.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(LEVEL_ACTION_SEND_MESSAGE_TEMPLATE_KEY, model, serverUser.getServerId());
|
||||
GuildMessageChannel targetChannel = channelService.getMessageChannelFromServer(serverUser.getServerId(), payload.getChannelId());
|
||||
FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, targetChannel)).thenAccept(unused -> {
|
||||
log.info("Send message to channel action sent a message to channel {} for user {} in server {}.", payload.getChannelId(), serverUser.getUserId(), serverUser.getServerId());
|
||||
}).exceptionally(throwable -> {
|
||||
log.warn("Send message to channel action failed to send a message to channel {} for user {} in server {}.", payload.getChannelId(), serverUser.getUserId(), serverUser.getServerId(), throwable);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
log.warn("Failed to load member {} in server {} for send message level action towards channel {}.", serverUser.getUserId(), serverUser.getServerId(), payload.getChannelId());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
if(!oldLevel.equals(aUserExperience.getLevelOrDefault())) { // this means the user changed level now, this is the path from gaining a lot of experience
|
||||
boolean jumpedLevelToMatch = oldLevel < levelAction.getLevel().getLevel() && aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
// this boolean means that the user did NOT have the action earlier, but does now (and more than that)
|
||||
return jumpedLevelToMatch || aUserExperience.getLevelOrDefault().equals(levelAction.getLevel().getLevel()); // or the user matches the level _exactly_, this is the path from normally gaining experience
|
||||
} else {
|
||||
// This case is useful for re-joining, because this means, that the user did _not_ change level, and already is somewhere way above
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareAction(LevelAction levelAction) {
|
||||
levelAction.setLoadedPayload(gson.fromJson(levelAction.getPayload(), SendMessageToChannelLevelActionPayload.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelActionPayload createPayload(Guild guild, String input) {
|
||||
if(!input.contains(";")) {
|
||||
throw new InputFormatException(input, "<#channel>;template_key");
|
||||
}
|
||||
String channelPart = input.substring(0, input.indexOf(";"));
|
||||
GuildChannel channel = ParseUtils.parseGuildChannelFromText(channelPart, guild);
|
||||
String templateKey = input.substring(input.indexOf(";") + 1);
|
||||
return SendMessageToChannelLevelActionPayload
|
||||
.builder()
|
||||
.channelId(channel.getIdLong())
|
||||
.templateKey(templateKey)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class SendMessageToChannelLevelActionMessageModel implements LevelActionPayload {
|
||||
private MemberDisplay memberDisplay;
|
||||
private Integer level;
|
||||
private Long experience;
|
||||
private String templateKey;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class SendMessageToChannelLevelActionPayload implements LevelActionPayload {
|
||||
private Long channelId;
|
||||
private String templateKey;
|
||||
}
|
||||
@@ -337,8 +337,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
.builder()
|
||||
.build();
|
||||
boolean userChangesLevel = !Objects.equals(newLevel.getLevel(), aUserExperience.getCurrentLevel().getLevel());
|
||||
Integer oldLevel = aUserExperience.getCurrentLevel() != null ? aUserExperience.getCurrentLevel().getLevel() : 0;
|
||||
if(userChangesLevel) {
|
||||
Integer oldLevel = aUserExperience.getCurrentLevel() != null ? aUserExperience.getCurrentLevel().getLevel() : 0;
|
||||
log.info("User {} in server {} changed level. New {}, Old {}.", member.getIdLong(),
|
||||
member.getGuild().getIdLong(), newLevel.getLevel(),
|
||||
oldLevel);
|
||||
@@ -373,7 +373,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
}
|
||||
aUserExperience.setMessageCount(aUserExperience.getMessageCount() + 1L);
|
||||
if(userChangesLevel && featureModeService.featureModeActive(ExperienceFeatureDefinition.EXPERIENCE, server, ExperienceFeatureMode.LEVEL_ACTION)) {
|
||||
levelActionService.applyLevelActionsToUser(aUserExperience)
|
||||
levelActionService.applyLevelActionsToUser(aUserExperience, oldLevel)
|
||||
.thenAccept(unused -> {
|
||||
log.info("Executed level actions for user {}.", userInServerId);
|
||||
})
|
||||
|
||||
@@ -49,6 +49,11 @@ public class LevelActionServiceBean implements LevelActionService {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user) {
|
||||
return applyLevelActionsToUser(user, user.getLevelOrDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user, Integer oldLevel) {
|
||||
if(levelActions == null || levelActions.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
@@ -60,8 +65,16 @@ public class LevelActionServiceBean implements LevelActionService {
|
||||
|
||||
Map<Integer, List<LevelAction>> actionConfigMap = new HashMap<>();
|
||||
|
||||
Map<String, LevelActionListener> actionStringListenerMap = levelActions
|
||||
.stream()
|
||||
.collect(Collectors.toMap(a -> a.getName().toLowerCase(), Function.identity()));
|
||||
|
||||
levelActionsOfUserInServer.forEach(levelAction -> {
|
||||
if(levelAction.getLevel().getLevel() > user.getLevelOrDefault()) {
|
||||
LevelActionListener listener = actionStringListenerMap.get(levelAction.getAction());
|
||||
if(listener == null) { // if for some reason the config is still in the database, but we don't have code for it anymore
|
||||
return;
|
||||
}
|
||||
if(!listener.shouldExecute(user, oldLevel, levelAction)) {
|
||||
return;
|
||||
}
|
||||
if(actionConfigMap.containsKey(levelAction.getLevel().getLevel())) {
|
||||
@@ -73,9 +86,6 @@ public class LevelActionServiceBean implements LevelActionService {
|
||||
}
|
||||
});
|
||||
|
||||
Map<String, LevelActionListener> actionStringListenerMap = levelActions
|
||||
.stream()
|
||||
.collect(Collectors.toMap(a -> a.getName().toLowerCase(), Function.identity()));
|
||||
|
||||
List<Integer> levels = actionConfigMap
|
||||
.keySet()
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AddRoleLevelActionTest {
|
||||
@InjectMocks
|
||||
private AddRoleLevelAction action;
|
||||
|
||||
@Mock
|
||||
private AUserExperience exp;
|
||||
|
||||
@Mock
|
||||
private LevelAction levelAction;
|
||||
|
||||
@Mock
|
||||
private AExperienceLevel level;
|
||||
|
||||
private final Integer LOW_LEVEL = 1;
|
||||
private final Integer MID_LEVEL = 2;
|
||||
private final Integer HIGH_LEVEL = 3;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(levelAction.getLevel()).thenReturn(level);
|
||||
}
|
||||
|
||||
@Test // rejoin too low case
|
||||
public void noLevelChangeActionNotReached() {
|
||||
executeTest(LOW_LEVEL, LOW_LEVEL, HIGH_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // re-join exact case
|
||||
public void noLevelChangeActionReached() {
|
||||
executeTest(LOW_LEVEL, LOW_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // normal leveling, higher action
|
||||
public void levelChangeActionNotReached() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, HIGH_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // normal leveling
|
||||
public void levelChangeActionReached() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, MID_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // a case for this is a large experience jump
|
||||
public void levelChangeActionOverJumped() {
|
||||
executeTest(LOW_LEVEL, HIGH_LEVEL, MID_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // a case for this is a re-join
|
||||
public void noLevelChangeActionOverJumped() {
|
||||
executeTest(HIGH_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // we dont want to re-execute previous actions (previous = lower level)
|
||||
public void levelChangeActionEqualsPrevious() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // we dont want to re-execute previous actions (previous = way lower level)
|
||||
public void levelChangeActionBelow() {
|
||||
executeTest(MID_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
private void executeTest(Integer oldLevel, Integer currentLevel, Integer actionLevel, boolean expected) {
|
||||
when(exp.getLevelOrDefault()).thenReturn(currentLevel);
|
||||
when(level.getLevel()).thenReturn(actionLevel);
|
||||
Assertions.assertThat(action.shouldExecute(exp, oldLevel, levelAction)).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RemoveMemberFromChannelLevelActionTest {
|
||||
|
||||
@InjectMocks
|
||||
private SendMessageToChannelLevelAction action;
|
||||
|
||||
@Mock
|
||||
private AUserExperience exp;
|
||||
|
||||
@Mock
|
||||
private LevelAction levelAction;
|
||||
|
||||
@Mock
|
||||
private AExperienceLevel level;
|
||||
|
||||
private final Integer LOW_LEVEL = 1;
|
||||
private final Integer MID_LEVEL = 2;
|
||||
private final Integer HIGH_LEVEL = 3;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(levelAction.getLevel()).thenReturn(level);
|
||||
}
|
||||
|
||||
@Test // rejoin too low case
|
||||
public void noLevelChangeActionNotReached() {
|
||||
executeTest(LOW_LEVEL, LOW_LEVEL, HIGH_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // re-join exact case
|
||||
public void noLevelChangeActionReached() {
|
||||
executeTest(LOW_LEVEL, LOW_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // normal leveling, higher action
|
||||
public void levelChangeActionNotReached() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, HIGH_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // normal leveling
|
||||
public void levelChangeActionReached() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, MID_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // a case for this is a large experience jump
|
||||
public void levelChangeActionOverJumped() {
|
||||
executeTest(LOW_LEVEL, HIGH_LEVEL, MID_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // a case for this is a re-join
|
||||
public void noLevelChangeActionOverJumped() {
|
||||
executeTest(HIGH_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // we dont want to re-execute previous actions (previous = lower level)
|
||||
public void levelChangeActionEqualsPrevious() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, LOW_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // we dont want to re-execute previous actions (previous = way lower level)
|
||||
public void levelChangeActionBelow() {
|
||||
executeTest(MID_LEVEL, HIGH_LEVEL, LOW_LEVEL, false);
|
||||
}
|
||||
|
||||
private void executeTest(Integer oldLevel, Integer currentLevel, Integer actionLevel, boolean expected) {
|
||||
when(exp.getLevelOrDefault()).thenReturn(currentLevel);
|
||||
when(level.getLevel()).thenReturn(actionLevel);
|
||||
Assertions.assertThat(action.shouldExecute(exp, oldLevel, levelAction)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>experience-tracking</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,15 +4,13 @@ import dev.sheldan.abstracto.experience.model.LevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public interface LevelActionListener {
|
||||
String getName();
|
||||
|
||||
void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container);
|
||||
|
||||
boolean shouldExecute(AUserExperience aUserExperience, LevelAction levelAction);
|
||||
boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction);
|
||||
|
||||
void prepareAction(LevelAction levelAction);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface LevelActionService {
|
||||
CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user);
|
||||
CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user, Integer oldLevel);
|
||||
List<String> getAvailableLevelActions();
|
||||
Optional<LevelActionListener> getLevelActionListenerForName(String name);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>giveaway</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>giveaway-impl</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>giveaway</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>giveaway-int</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>giveaway</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>image-generation</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>image-generation-impl</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>image-generation</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>image-generation-int</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>image-generation</artifactId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>invite-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>invite-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation-int</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>link-embed</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>link-embed</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>logging</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>logging</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>modmail</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -38,6 +38,12 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.core</groupId>
|
||||
<artifactId>metrics-int</artifactId>
|
||||
|
||||
@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
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.MemberService;
|
||||
import dev.sheldan.abstracto.core.service.UserService;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailThreadClosedException;
|
||||
@@ -40,7 +40,7 @@ public class AnonReply extends AbstractConditionableCommand {
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
@@ -52,8 +52,8 @@ public class AnonReply extends AbstractConditionableCommand {
|
||||
throw new ModMailThreadClosedException();
|
||||
}
|
||||
Long threadId = modMailThread.getId();
|
||||
return memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
|
||||
modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), true, member)
|
||||
return userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenCompose(user ->
|
||||
modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), true, user, commandContext.getGuild())
|
||||
).thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@ public class Close extends AbstractConditionableCommand {
|
||||
.builder()
|
||||
.closingMember(commandContext.getAuthor())
|
||||
.notifyUser(true)
|
||||
.channel(commandContext.getChannel())
|
||||
.log(true)
|
||||
.note(note)
|
||||
.build();
|
||||
@@ -112,19 +111,18 @@ public class Close extends AbstractConditionableCommand {
|
||||
ClosingContext context = ClosingContext
|
||||
.builder()
|
||||
.closingMember(event.getMember())
|
||||
.channel(event.getChannel())
|
||||
.notifyUser(!silently)
|
||||
.log(log)
|
||||
.note(note)
|
||||
.build();
|
||||
return interactionService.replyEmbed(CLOSE_RESPONSE, event)
|
||||
.thenCompose(interactionHook -> self.closeThread(context))
|
||||
.thenCompose(interactionHook -> self.closeThread(context, event.getChannelIdLong()))
|
||||
.thenApply(aVoid -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> closeThread(ClosingContext closingContext) {
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(closingContext.getChannel().getIdLong());
|
||||
public CompletableFuture<Void> closeThread(ClosingContext closingContext, Long channelId) {
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(channelId);
|
||||
if(ModMailThreadState.CLOSED.equals(modMailThread.getState()) || ModMailThreadState.CLOSING.equals(modMailThread.getState())) {
|
||||
throw new ModMailThreadClosedException();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementS
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
@@ -44,7 +45,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
@Slf4j
|
||||
public class Contact extends AbstractConditionableCommand {
|
||||
|
||||
private static final String CONTACT_PARAMETER = "contact";
|
||||
private static final String COMMAND_NAME = "contact";
|
||||
private static final String USER_PARMETER = "user";
|
||||
private static final String MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE = "modmail_thread_already_exists";
|
||||
private static final String CONTACT_RESPONSE = "contact_response";
|
||||
@@ -87,24 +88,21 @@ public class Contact extends AbstractConditionableCommand {
|
||||
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInTextChannelList(MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE, model, commandContext.getChannel());
|
||||
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());
|
||||
} else {
|
||||
return modMailThreadService.createModMailThreadForUser(targetUser, null, false, commandContext.getUndoActions())
|
||||
.thenCompose(unused -> modMailThreadService.sendContactNotification(targetUser, unused, commandContext.getChannel()))
|
||||
return modMailThreadService.createModMailThreadForUser(targetUser.getUser(), targetUser.getGuild(), null, false, commandContext.getUndoActions())
|
||||
.thenCompose(unused -> modMailThreadService.sendContactNotification(targetUser.getUser(), unused, commandContext.getChannel()))
|
||||
.thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
Member member = slashCommandParameterService.getCommandOption(USER_PARMETER, event, Member.class);
|
||||
if(!member.getGuild().equals(event.getGuild())) {
|
||||
throw new EntityGuildMismatchException();
|
||||
}
|
||||
AUserInAServer user = userManagementService.loadOrCreateUser(member);
|
||||
User user = slashCommandParameterService.getCommandOption(USER_PARMETER, event, User.class);
|
||||
AUserInAServer userInAServer = userManagementService.loadOrCreateUser(event.getGuild().getIdLong(), user.getIdLong());
|
||||
// if this AUserInAServer already has an open thread, we should instead post a message
|
||||
// containing a link to the channel, instead of opening a new one
|
||||
if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) {
|
||||
log.info("Modmail thread for user {} in server {} already exists. Notifying user {}.", event.getMember().getId(), event.getGuild().getId(), user.getUserReference().getId());
|
||||
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
|
||||
if(modMailThreadManagementService.hasOpenModMailThreadForUser(userInAServer)) {
|
||||
log.info("Modmail thread for userInAServer {} in server {} already exists. Notifying userInAServer {}.", event.getMember().getId(), event.getGuild().getId(), userInAServer.getUserReference().getId());
|
||||
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(userInAServer);
|
||||
ModMailThreadExistsModel model = ModMailThreadExistsModel
|
||||
.builder()
|
||||
.existingModMailThread(existingThread)
|
||||
@@ -114,9 +112,9 @@ public class Contact extends AbstractConditionableCommand {
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
} else {
|
||||
CompletableFuture<InteractionHook> response = interactionService.replyEmbed(CONTACT_RESPONSE, event);
|
||||
CompletableFuture<MessageChannel> threadFuture = modMailThreadService.createModMailThreadForUser(member, null, false, new ArrayList<>());
|
||||
CompletableFuture<MessageChannel> threadFuture = modMailThreadService.createModMailThreadForUser(user, event.getGuild(), null, false, new ArrayList<>());
|
||||
return CompletableFuture.allOf(response, threadFuture)
|
||||
.thenCompose(unused -> modMailThreadService.sendContactNotification(member, threadFuture.join(), response.join()))
|
||||
.thenCompose(unused -> modMailThreadService.sendContactNotification(user, threadFuture.join(), response.join()))
|
||||
.thenApply(o -> CommandResult.fromSuccess());
|
||||
}
|
||||
}
|
||||
@@ -126,7 +124,7 @@ public class Contact extends AbstractConditionableCommand {
|
||||
Parameter responseText = Parameter
|
||||
.builder()
|
||||
.name(USER_PARMETER)
|
||||
.type(Member.class)
|
||||
.type(User.class)
|
||||
.templated(true)
|
||||
.build();
|
||||
List<Parameter> parameters = Arrays.asList(responseText);
|
||||
@@ -139,11 +137,11 @@ public class Contact extends AbstractConditionableCommand {
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
|
||||
.commandName(CONTACT_PARAMETER)
|
||||
.commandName(COMMAND_NAME)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(CONTACT_PARAMETER)
|
||||
.name(COMMAND_NAME)
|
||||
.module(ModMailModuleDefinition.MODMAIL)
|
||||
.parameters(parameters)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package dev.sheldan.abstracto.modmail.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
|
||||
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.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailMode;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailThreadClosedException;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailThreadState;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.InteractionHook;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DenyModmailAppeal extends AbstractConditionableCommand {
|
||||
|
||||
private static final String COMMAND_NAME = "denyappeal";
|
||||
private static final String FULL_COMMAND_NAME = "denyModmailAppeal";
|
||||
private static final String REASON_PARAMETER = "reason";
|
||||
|
||||
private static final String RESPONSE_TEMPLATE = "denyModmailAppeal_response";
|
||||
|
||||
@Autowired
|
||||
private ModMailContextCondition requiresModMailCondition;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadService modMailThreadService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(event.getChannel().getIdLong());
|
||||
if(ModMailThreadState.CLOSED.equals(modMailThread.getState()) || ModMailThreadState.CLOSING.equals(modMailThread.getState())) {
|
||||
throw new ModMailThreadClosedException();
|
||||
}
|
||||
String reason = slashCommandParameterService.getCommandOption(REASON_PARAMETER, event, String.class);
|
||||
CompletableFuture<InteractionHook> response = interactionService.replyEmbed(RESPONSE_TEMPLATE, event);
|
||||
CompletableFuture<Void> threadFuture = modMailThreadService.rejectAppeal(modMailThread, reason, event.getMember());
|
||||
return CompletableFuture.allOf(response, threadFuture)
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ModMailFeatureDefinition.MOD_MAIL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
Parameter responseText = Parameter
|
||||
.builder()
|
||||
.name(REASON_PARAMETER)
|
||||
.type(String.class)
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
List<Parameter> parameters = Arrays.asList(responseText);
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
|
||||
.commandName(COMMAND_NAME)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(FULL_COMMAND_NAME)
|
||||
.module(ModMailModuleDefinition.MODMAIL)
|
||||
.parameters(parameters)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.help(helpInfo)
|
||||
.slashCommandOnly(true)
|
||||
.supportsEmbedException(true)
|
||||
.templated(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommandCondition> getConditions() {
|
||||
List<CommandCondition> conditions = super.getConditions();
|
||||
conditions.add(requiresModMailCondition);
|
||||
return conditions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return List.of(ModMailMode.MOD_MAIL_APPEALS);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ 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.MemberService;
|
||||
import dev.sheldan.abstracto.core.service.UserService;
|
||||
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
|
||||
import dev.sheldan.abstracto.modmail.exception.ModMailThreadClosedException;
|
||||
@@ -39,7 +40,7 @@ public class Reply extends AbstractConditionableCommand {
|
||||
private ModMailThreadManagementService modMailThreadManagementService;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
@@ -50,8 +51,8 @@ public class Reply extends AbstractConditionableCommand {
|
||||
throw new ModMailThreadClosedException();
|
||||
}
|
||||
Long threadId = modMailThread.getId();
|
||||
return memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
|
||||
modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), false, member)
|
||||
return userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenCompose(user ->
|
||||
modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), false, user, commandContext.getGuild())
|
||||
).thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@@ -65,7 +66,7 @@ public class Reply extends AbstractConditionableCommand {
|
||||
.optional(true)
|
||||
.templated(true)
|
||||
.build();
|
||||
List<Parameter> parameters = Arrays.asList(responseText);
|
||||
List<Parameter> parameters = List.of(responseText);
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("reply")
|
||||
|
||||
@@ -14,6 +14,7 @@ import dev.sheldan.abstracto.modmail.model.dto.ServiceChoicesPayload;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -25,7 +26,7 @@ import java.util.ArrayList;
|
||||
public class ModMailInitialButtonListener implements ButtonClickedListener {
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
private GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
private ModMailThreadService modMailThreadService;
|
||||
@@ -51,20 +52,19 @@ public class ModMailInitialButtonListener implements ButtonClickedListener {
|
||||
Long userId = choices.getUserId();
|
||||
log.debug("Executing action for creationg a modmail thread in server {} for user {}.", chosenServer.getServerId(), userId);
|
||||
ArrayList<UndoActionInstance> undoActions = new ArrayList<>();
|
||||
memberService.getMemberInServerAsync(chosenServer.getServerId(), userId)
|
||||
.thenCompose(member -> channelService.retrieveMessageInChannel(model.getEvent().getChannel(), choices.getMessageId())
|
||||
Guild guild = guildService.getGuildById(chosenServer.getServerId());
|
||||
channelService.retrieveMessageInChannel(model.getEvent().getChannel(), choices.getMessageId())
|
||||
.thenCompose(originalMessage -> {
|
||||
try {
|
||||
return modMailThreadService.createModMailThreadForUser(member, originalMessage, true, undoActions);
|
||||
return modMailThreadService.createModMailThreadForUser(model.getEvent().getUser(), guild, originalMessage, true, undoActions);
|
||||
} catch (Exception ex) {
|
||||
log.error("Failed to setup thread correctly", ex);
|
||||
undoActionService.performActions(undoActions);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.thenAccept(unused -> self.cleanup(model)))
|
||||
.exceptionally(throwable -> {
|
||||
log.error("Failed to setup thread correctly", throwable);
|
||||
.thenAccept(unused -> self.cleanup(model)).exceptionally(throwable -> {
|
||||
log.warn("Failed to setup modmail thread.");
|
||||
undoActionService.performActions(undoActions);
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.listener.MessageDeletedModel;
|
||||
import dev.sheldan.abstracto.core.service.MemberService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.core.service.UserService;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailMessage;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
|
||||
@@ -33,7 +34,7 @@ public class ModMailMessageDeletedListener implements AsyncMessageDeletedListene
|
||||
private ModMailMessageDeletedListener self;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MessageDeletedModel model) {
|
||||
@@ -47,8 +48,8 @@ public class ModMailMessageDeletedListener implements AsyncMessageDeletedListene
|
||||
Long channelId = thread.getChannel().getId();
|
||||
Long serverId = thread.getServer().getId();
|
||||
log.info("Deleting message for mod mail thread {} in channel {} in server {}.", thread.getId(), channelId, serverId);
|
||||
memberService.getMemberInServerAsync(model.getServerId(), modMailMessage.getThreadReference().getUser().getUserReference().getId()).thenAccept(member -> {
|
||||
CompletableFuture<Void> dmDeletePromise = messageService.deleteMessageInChannelWithUser(member.getUser(), dmMessageId);
|
||||
userService.retrieveUserForId(modMailMessage.getThreadReference().getUser().getUserReference().getId()).thenAccept(user -> {
|
||||
CompletableFuture<Void> dmDeletePromise = messageService.deleteMessageInChannelWithUser(user, dmMessageId);
|
||||
CompletableFuture<Void> channelDeletePromise;
|
||||
if(hasMessageInChannel) {
|
||||
channelDeletePromise = messageService.deleteMessageInChannelInServer(serverId, channelId, channelMessage);
|
||||
|
||||
@@ -10,9 +10,11 @@ import dev.sheldan.abstracto.core.models.FullUserInServer;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.listener.MessageUpdatedModel;
|
||||
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.MemberService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.core.service.UserService;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailMessage;
|
||||
import dev.sheldan.abstracto.modmail.model.template.ModMailModeratorReplyModel;
|
||||
@@ -24,6 +26,7 @@ import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -45,9 +48,6 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
|
||||
@Autowired
|
||||
private CommandService commandService;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@@ -66,6 +66,12 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
|
||||
@Autowired
|
||||
private ModMailThreadService modMailThreadService;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MessageUpdatedModel model) {
|
||||
CachedMessage messageBefore = model.getBefore();
|
||||
@@ -85,7 +91,7 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
|
||||
log.info("Edit did not contain the original command to retrieve the parameters for. Resulting to {}.", DEFAULT_COMMAND_FOR_MODMAIL_EDIT);
|
||||
}
|
||||
CompletableFuture<Parameters> parameterParseFuture = commandService.getParametersForCommand(commandName, message);
|
||||
CompletableFuture<Member> loadTargetUser = memberService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getThreadReference().getUser().getUserReference().getId());
|
||||
CompletableFuture<User> loadTargetUser = userService.retrieveUserForId(modMailMessage.getThreadReference().getUser().getUserReference().getId());
|
||||
CompletableFuture<Member> loadEditingUser = memberService.getMemberInServerAsync(messageBefore.getServerId(), modMailMessage.getAuthor().getUserReference().getId());
|
||||
CompletableFuture.allOf(parameterParseFuture, loadTargetUser, loadEditingUser).thenAccept(unused ->
|
||||
self.updateMessageInThread(message, parameterParseFuture.join(), loadTargetUser.join(), loadEditingUser.join())
|
||||
@@ -100,15 +106,10 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateMessageInThread(Message loadedMessage, Parameters parameters, Member targetMember, Member editingUser) {
|
||||
public void updateMessageInThread(Message loadedMessage, Parameters parameters, User user, Member editingUser) {
|
||||
String newText = (String) parameters.getParameters().get(0);
|
||||
Optional<ModMailMessage> messageOptional = modMailMessageManagementService.getByMessageIdOptional(loadedMessage.getIdLong());
|
||||
messageOptional.ifPresent(modMailMessage -> {
|
||||
FullUserInServer fullThreadUser = FullUserInServer
|
||||
.builder()
|
||||
.aUserInAServer(modMailMessage.getThreadReference().getUser())
|
||||
.member(targetMember)
|
||||
.build();
|
||||
List<String> imageUrls = loadedMessage
|
||||
.getAttachments()
|
||||
.stream()
|
||||
@@ -128,7 +129,7 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
|
||||
.attachedImageUrls(imageUrls)
|
||||
.remainingAttachments(otherAttachments)
|
||||
.anonymous(modMailMessage.getAnonymous())
|
||||
.threadUser(fullThreadUser);
|
||||
.userDisplay(UserDisplay.fromUser(user));
|
||||
if(modMailMessage.getAnonymous()) {
|
||||
modMailModeratorReplyModelBuilder.moderator(memberService.getBotInGuild(modMailMessage.getThreadReference().getServer()));
|
||||
} else {
|
||||
@@ -143,13 +144,13 @@ public class ModMailMessageEditedListener implements AsyncMessageUpdatedListener
|
||||
log.debug("Editing message {} in mod mail channel {} for thread {} in server {} as well.", modMailMessage.getCreatedMessageInChannel(), channel.getId(), threadId, serverId);
|
||||
channelService.editMessageInAChannel(messageToSend, channel, modMailMessage.getCreatedMessageInChannel());
|
||||
}
|
||||
log.debug("Editing message {} in DM channel with user {} for thread {} in server {}.", modMailMessage.getCreatedMessageInDM(), targetMember.getUser().getIdLong(), threadId, serverId);
|
||||
messageService.editMessageInDMChannel(targetMember.getUser(), messageToSend, modMailMessage.getCreatedMessageInDM());
|
||||
log.debug("Editing message {} in DM channel with user {} for thread {} in server {}.", modMailMessage.getCreatedMessageInDM(), user.getIdLong(), threadId, serverId);
|
||||
messageService.editMessageInDMChannel(user, messageToSend, modMailMessage.getCreatedMessageInDM());
|
||||
});
|
||||
|
||||
if(!messageOptional.isPresent()) {
|
||||
log.warn("Message {} of user {} in channel {} for server {} for thread about user {} could not be found in the mod mail messages when updating the text.",
|
||||
loadedMessage.getIdLong(), editingUser.getIdLong(), loadedMessage.getChannel().getIdLong(), loadedMessage.getGuild().getIdLong(), targetMember.getIdLong());
|
||||
loadedMessage.getIdLong(), editingUser.getIdLong(), loadedMessage.getChannel().getIdLong(), loadedMessage.getGuild().getIdLong(), user.getIdLong());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,9 +36,6 @@ public class ModMailMessageListener implements PrivateMessageReceivedListener {
|
||||
@Autowired
|
||||
private UserManagementService userManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void execute(Message message) {
|
||||
|
||||
@@ -19,9 +19,6 @@ public class ModMailRoleServiceBean implements ModMailRoleService {
|
||||
@Autowired
|
||||
private CommandService commandService;
|
||||
|
||||
@Autowired
|
||||
private FeatureManagementService featureManagementService;
|
||||
|
||||
@Override
|
||||
public void addRoleToModMailRoles(ARole role) {
|
||||
log.info("Adding role {} to modmail roles in server {}.", role.getId(), role.getServer().getId());
|
||||
|
||||
@@ -8,10 +8,7 @@ import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.metric.service.CounterMetric;
|
||||
import dev.sheldan.abstracto.core.metric.service.MetricService;
|
||||
import dev.sheldan.abstracto.core.metric.service.MetricTag;
|
||||
import dev.sheldan.abstracto.core.models.FeatureValidationResult;
|
||||
import dev.sheldan.abstracto.core.models.FullGuild;
|
||||
import dev.sheldan.abstracto.core.models.FullUserInServer;
|
||||
import dev.sheldan.abstracto.core.models.UndoActionInstance;
|
||||
import dev.sheldan.abstracto.core.models.*;
|
||||
import dev.sheldan.abstracto.core.models.database.*;
|
||||
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
|
||||
import dev.sheldan.abstracto.core.service.*;
|
||||
@@ -20,6 +17,7 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.moderation.service.BanService;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatureConfig;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
|
||||
import dev.sheldan.abstracto.modmail.config.ModMailMode;
|
||||
@@ -52,6 +50,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -112,6 +111,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
@Autowired
|
||||
private GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
private BanService banService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@@ -188,22 +190,21 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
public static final String MODMAIL_INITIAL_ORIGIN = "modmailInitial";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<MessageChannel> createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions) {
|
||||
Long serverId = member.getGuild().getIdLong();
|
||||
User user = member.getUser();
|
||||
AServer server = serverManagementService.loadServer(member.getGuild().getIdLong());
|
||||
public CompletableFuture<MessageChannel> createModMailThreadForUser(User user, Guild guild, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions) {
|
||||
Long serverId = guild.getIdLong();
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
metricService.incrementCounter(MODMAIL_THREAD_CREATED_COUNTER);
|
||||
ModMailChannelNameModel model = ModMailChannelNameModel
|
||||
.builder()
|
||||
.serverId(serverId)
|
||||
.userId(member.getIdLong())
|
||||
.userId(user.getIdLong())
|
||||
.randomText(RandomStringUtils.randomAlphanumeric(25))
|
||||
.uuid(UUID.randomUUID().toString())
|
||||
.currentDate(Instant.now())
|
||||
.build();
|
||||
String channelName = templateService.renderTemplate(TEXT_CHANNEL_NAME_TEMPLATE_KEY, model, serverId);
|
||||
if (featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, serverId, ModMailMode.THREAD_CONTAINER)) {
|
||||
MessageToSend notificationMessageToSend = getModmailNotificationMessageToSend(member, null, serverId, false);
|
||||
MessageToSend notificationMessageToSend = getModmailNotificationMessageToSend(user, null, serverId, false);
|
||||
Optional<GuildMessageChannel> modmailContainerOptional = postTargetService.getPostTargetChannel(ModMailPostTargets.MOD_MAIL_CONTAINER, serverId);
|
||||
if(modmailContainerOptional.isEmpty()) {
|
||||
throw new AbstractoRunTimeException("Modmail thread container not setup.");
|
||||
@@ -219,7 +220,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
.thenCompose(unused -> channelService.createThreadWithStarterMessage(textChannel, channelName, notificationMessage.get(0).join().getIdLong()))
|
||||
.thenCompose(threadChannel -> {
|
||||
undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, threadChannel.getIdLong()));
|
||||
return self.performModMailThreadSetup(member, initialMessage, threadChannel, userInitiated, undoActions)
|
||||
return self.performModMailThreadSetup(user, initialMessage, threadChannel, userInitiated, undoActions)
|
||||
.thenCompose(unused -> CompletableFuture.completedFuture(threadChannel));
|
||||
});
|
||||
} else {
|
||||
@@ -228,7 +229,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
CompletableFuture<TextChannel> textChannelFuture = channelService.createTextChannel(channelName, server, categoryId);
|
||||
return textChannelFuture.thenCompose(channel -> {
|
||||
undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, channel.getIdLong()));
|
||||
return self.performModMailThreadSetup(member, initialMessage, channel, userInitiated, undoActions)
|
||||
return self.performModMailThreadSetup(user, initialMessage, channel, userInitiated, undoActions)
|
||||
.thenCompose(unused -> CompletableFuture.completedFuture(channel));
|
||||
});
|
||||
}
|
||||
@@ -236,21 +237,21 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CompletableFuture<Void> sendContactNotification(Member member, MessageChannel messageChannel, MessageChannel feedBackChannel) {
|
||||
public CompletableFuture<Void> sendContactNotification(User user, MessageChannel messageChannel, MessageChannel feedBackChannel) {
|
||||
ContactNotificationModel model = ContactNotificationModel
|
||||
.builder()
|
||||
.createdChannel(messageChannel)
|
||||
.targetMember(member)
|
||||
.userDisplay(UserDisplay.fromUser(user))
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannelList(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, feedBackChannel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, InteractionHook interactionHook) {
|
||||
public CompletableFuture<Void> sendContactNotification(User user, MessageChannel createdMessageChannel, InteractionHook interactionHook) {
|
||||
ContactNotificationModel model = ContactNotificationModel
|
||||
.builder()
|
||||
.createdChannel(createdMessageChannel)
|
||||
.targetMember(member)
|
||||
.userDisplay(UserDisplay.fromUser(user))
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, interactionHook));
|
||||
}
|
||||
@@ -258,7 +259,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
/**
|
||||
* This method is responsible for creating the instance in the database, sending the header in the newly created text channel and forwarding the initial message
|
||||
* by the user (if any), after this is complete, this method executes the method to perform the mod mail notification.
|
||||
* @param member The {@link Member} for which a {@link ModMailThread} is being created
|
||||
* @param user The {@link User} for which a {@link ModMailThread} is being created
|
||||
* @param initialMessage The {@link Message} which was sent by the user to open a thread, this is null, if the thread was opened via a command
|
||||
* @param channel The created {@link TextChannel} in which the mod mail thread is dealt with
|
||||
* @param userInitiated Whether the thread was initiated by a member
|
||||
@@ -266,33 +267,33 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* @return A {@link CompletableFuture future} which completes when the setup is done
|
||||
*/
|
||||
@Transactional
|
||||
public CompletableFuture<Void> performModMailThreadSetup(Member member, Message initialMessage, GuildMessageChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions) {
|
||||
log.info("Performing modmail thread setup for channel {} for user {} in server {}. It was initiated by a user: {}.", channel.getIdLong(), member.getId(), channel.getGuild().getId(), userInitiated);
|
||||
CompletableFuture<Void> headerFuture = sendModMailHeader(channel, member);
|
||||
public CompletableFuture<Void> performModMailThreadSetup(User user, Message initialMessage, GuildMessageChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions) {
|
||||
log.info("Performing modmail thread setup for channel {} for user {} in server {}. It was initiated by a user: {}.", channel.getIdLong(), user.getId(), channel.getGuild().getId(), userInitiated);
|
||||
CompletableFuture<Void> headerFuture = sendModMailHeader(channel, user);
|
||||
CompletableFuture<Message> userReplyMessage;
|
||||
if(initialMessage != null){
|
||||
log.info("Sending initial message {} of user {} to modmail thread {}.", initialMessage.getId(), member.getId(), channel.getId());
|
||||
userReplyMessage = self.sendUserReply(channel, 0L, initialMessage, member, false);
|
||||
log.info("Sending initial message {} of user {} to modmail thread {}.", initialMessage.getId(), user.getId(), channel.getId());
|
||||
userReplyMessage = self.sendUserReply(channel, 0L, initialMessage, false);
|
||||
} else {
|
||||
log.info("No initial message to send.");
|
||||
userReplyMessage = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
CompletableFuture notificationFuture;
|
||||
if (userInitiated) {
|
||||
notificationFuture = self.sendModMailNotification(member, channel);
|
||||
notificationFuture = self.sendModMailNotification(user, channel);
|
||||
} else {
|
||||
notificationFuture = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
return CompletableFuture.allOf(headerFuture, notificationFuture, userReplyMessage).thenAccept(aVoid -> {
|
||||
undoActions.clear();
|
||||
self.setupModMailThreadInDB(initialMessage, channel, member, userReplyMessage.join());
|
||||
self.setupModMailThreadInDB(initialMessage, channel, user, userReplyMessage.join());
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void setupModMailThreadInDB(Message initialMessage, GuildMessageChannel channel, Member member, Message sendMessage) {
|
||||
public void setupModMailThreadInDB(Message initialMessage, GuildMessageChannel channel, User user, Message sendMessage) {
|
||||
log.info("Persisting info about modmail thread {} in database.", channel.getIdLong());
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(channel.getGuild().getIdLong(), user.getIdLong());
|
||||
ModMailThread thread = createThreadObject(channel, aUserInAServer);
|
||||
if(initialMessage != null) {
|
||||
log.debug("Adding initial message {} to modmail thread in channel {}.", initialMessage.getId(), channel.getId());
|
||||
@@ -302,19 +303,19 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
|
||||
/**
|
||||
* Sends the message containing the pings to notify the staff members to handle the opened {@link ModMailThread}
|
||||
* @param member The {@link FullUserInServer} which opened the thread
|
||||
* @param user The {@link FullUserInServer} which opened the thread
|
||||
* @param channel The created {@link GuildMessageChannel} in which the mod mail thread is dealt with
|
||||
* @return A {@link CompletableFuture future} which completes when the notification has been sent
|
||||
*/
|
||||
@Transactional
|
||||
public CompletableFuture<Void> sendModMailNotification(Member member, GuildMessageChannel channel) {
|
||||
Long serverId = member.getGuild().getIdLong();
|
||||
MessageToSend messageToSend = getModmailNotificationMessageToSend(member, channel, serverId, true);
|
||||
public CompletableFuture<Void> sendModMailNotification(User user, GuildMessageChannel channel) {
|
||||
Long serverId = channel.getGuild().getIdLong();
|
||||
MessageToSend messageToSend = getModmailNotificationMessageToSend(user, channel, serverId, true);
|
||||
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_PING, serverId));
|
||||
}
|
||||
|
||||
private MessageToSend getModmailNotificationMessageToSend(Member member, GuildMessageChannel channel, Long serverId, boolean pingRole) {
|
||||
log.info("Sending modmail notification for new modmail thread about user {} in server {}.", member.getId(), serverId);
|
||||
private MessageToSend getModmailNotificationMessageToSend(User user, GuildMessageChannel channel, Long serverId, boolean pingRole) {
|
||||
log.info("Sending modmail notification for new modmail thread about user {} in server {}.", user.getId(), serverId);
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
List<ModMailRole> rolesToPing;
|
||||
if(pingRole) {
|
||||
@@ -322,10 +323,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
} else {
|
||||
rolesToPing = new ArrayList<>();
|
||||
}
|
||||
log.debug("Pinging {} roles to notify about modmail thread about user {} in server {}.", rolesToPing.size(), member.getId(), serverId);
|
||||
log.debug("Pinging {} roles to notify about modmail thread about user {} in server {}.", rolesToPing.size(), user.getId(), serverId);
|
||||
ModMailNotificationModel modMailNotificationModel = ModMailNotificationModel
|
||||
.builder()
|
||||
.member(member)
|
||||
.userDisplay(UserDisplay.fromUser(user))
|
||||
.roles(rolesToPing)
|
||||
.channel(channel)
|
||||
.build();
|
||||
@@ -370,24 +371,57 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
if(!servers.isEmpty()) {
|
||||
log.info("There are {} shared servers between user and the bot.", servers.size());
|
||||
List<ServerChoice> availableGuilds = new ArrayList<>();
|
||||
Set<Long> alreadyConsideredServers = new HashSet<>();
|
||||
for (AServer server : servers) {
|
||||
// only take the servers in which mod mail is actually enabled, would not make much sense to make the
|
||||
// other servers available
|
||||
if (featureFlagService.isFeatureEnabled(modMailFeatureConfig, server)) {
|
||||
FullGuild guild = FullGuild
|
||||
.builder()
|
||||
.guild(guildService.getGuildById(server.getId()))
|
||||
.server(server)
|
||||
.build();
|
||||
boolean possibleForModmail = featureFlagService.isFeatureEnabled(modMailFeatureConfig, server);
|
||||
if (possibleForModmail) {
|
||||
Guild guild = guildService.getGuildById(server.getId());
|
||||
ServerChoice serverChoice = ServerChoice
|
||||
.builder()
|
||||
.serverId(guild.getGuild().getIdLong())
|
||||
.serverName(guild.getGuild().getName())
|
||||
.serverId(guild.getIdLong())
|
||||
.serverName(guild.getName())
|
||||
.build();
|
||||
availableGuilds.add(serverChoice);
|
||||
}
|
||||
alreadyConsideredServers.add(server.getId());
|
||||
}
|
||||
|
||||
List<AServer> restOfKnownServers = serverManagementService.getAllServers()
|
||||
.stream()
|
||||
.filter(server -> alreadyConsideredServers.contains(server.getId()))
|
||||
.toList();
|
||||
for (AServer server : restOfKnownServers) {
|
||||
boolean possibleForModmail = false;
|
||||
Long actualServerId = 0L;
|
||||
Long potentialMainServer = configService.getLongValue(ModMailFeatureConfig.MOD_MAIL_APPEAL_SERVER, server.getId()); // what _other_ server is the appeal server
|
||||
if(potentialMainServer != 0) {
|
||||
if(featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, potentialMainServer, ModMailMode.MOD_MAIL_APPEALS)) {
|
||||
Long configuredAppealServerId = configService.getLongValue(ModMailFeatureConfig.MOD_MAIL_APPEAL_SERVER, potentialMainServer);
|
||||
if(configuredAppealServerId != 0 && configuredAppealServerId.equals(server.getId())) { // if the other server has set the current server as the appeal config
|
||||
Guild otherGuild = guildService.getGuildById(potentialMainServer);
|
||||
if(otherGuild != null) { // check if we are part of that server
|
||||
possibleForModmail = true;
|
||||
actualServerId = potentialMainServer;
|
||||
log.info("Server {} was available, because it is using server {} as a mod mail appeal server.", server.getId(), otherGuild.getIdLong());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info("Server {} has set the appeal server {}, but that server does not have mod mail appeals enabled.", server.getId(), potentialMainServer);
|
||||
}
|
||||
}
|
||||
if(possibleForModmail) {
|
||||
Guild guild = guildService.getGuildById(actualServerId);
|
||||
ServerChoice serverChoice = ServerChoice
|
||||
.builder()
|
||||
.serverId(guild.getIdLong())
|
||||
.serverName(guild.getName())
|
||||
.build();
|
||||
availableGuilds.add(serverChoice);
|
||||
}
|
||||
}
|
||||
log.info("There were {} shared servers found which have modmail enabled.", availableGuilds.size());
|
||||
log.info("There were {} available servers found.", availableGuilds.size());
|
||||
// if more than 1 server is available, show a choice dialog
|
||||
ArrayList<UndoActionInstance> undoActions = new ArrayList<>();
|
||||
if(availableGuilds.size() > 1) {
|
||||
@@ -415,20 +449,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
} else if(availableGuilds.size() == 1) {
|
||||
// if exactly one server is available, open the thread directly
|
||||
Long chosenServerId = availableGuilds.get(0).getServerId();
|
||||
Guild guild = guildService.getGuildById(chosenServerId);
|
||||
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, true, undoActions).thenApply(messageChannel -> null);
|
||||
} catch (Exception exception) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
future.completeExceptionally(exception);
|
||||
return future;
|
||||
}
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to setup thread correctly", throwable);
|
||||
undoActionService.performActions(undoActions);
|
||||
return null;
|
||||
});
|
||||
createModMailThreadForUser(initialMessage.getAuthor(), guild , initialMessage, true, undoActions)
|
||||
.thenAccept(messageChannel -> {
|
||||
log.info("Setup modmail thread for user {} in guild {}.", initialMessage.getAuthor().getIdLong(), guild.getIdLong());
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to setup modmail channel in guild {} for user {}.", guild.getIdLong(), initialMessage.getAuthor().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
log.info("No server available to open a modmail thread in.");
|
||||
// in case there is no server available, send an error message
|
||||
@@ -451,18 +480,17 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* Method used to send the header of a newly created mod mail thread. This message contains information about
|
||||
* the user which the thread is about
|
||||
* @param channel The {@link GuildMessageChannel} in which the mod mail thread is present in
|
||||
* @param member The {@link Member} which the {@link ModMailThread} is about
|
||||
* @param user The {@link User} which the {@link ModMailThread} is about
|
||||
*/
|
||||
private CompletableFuture<Void> sendModMailHeader(GuildMessageChannel channel, Member member) {
|
||||
private CompletableFuture<Void> sendModMailHeader(GuildMessageChannel channel, User user) {
|
||||
log.debug("Sending modmail thread header for tread in channel {} on server {}.", channel.getIdLong(), channel.getGuild().getId());
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(channel.getGuild().getIdLong(), user.getIdLong());
|
||||
ModMailThread latestThread = modMailThreadManagementService.getLatestModMailThread(aUserInAServer);
|
||||
List<ModMailThread> oldThreads = modMailThreadManagementService.getModMailThreadForUser(aUserInAServer);
|
||||
ModMailThreaderHeader header = ModMailThreaderHeader
|
||||
.builder()
|
||||
.member(member)
|
||||
.userDisplay(UserDisplay.fromUser(user))
|
||||
.latestModMailThread(latestThread)
|
||||
.memberJoinDate(member.getTimeJoined().toInstant())
|
||||
.pastModMailThreadCount((long)oldThreads.size())
|
||||
.build();
|
||||
List<CompletableFuture<Message>> messages = channelService.sendEmbedTemplateInTextChannelList("modmail_thread_header", header, channel);
|
||||
@@ -476,18 +504,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
Long modmailThreadId = modMailThread.getId();
|
||||
metricService.incrementCounter(MDOMAIL_THREAD_MESSAGE_RECEIVED);
|
||||
log.debug("Relaying message {} to modmail thread {} for user {} to server {}.", messageFromUser.getId(), modMailThread.getId(), messageFromUser.getAuthor().getIdLong(), modMailThread.getServer().getId());
|
||||
return memberService.getMemberInServerAsync(modMailThread.getServer().getId(), messageFromUser.getAuthor().getIdLong()).thenCompose(member ->
|
||||
self.relayMessage(messageFromUser, serverId, channelId, modmailThreadId, member)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Message> relayMessage(Message messageFromUser, Long serverId, Long channelId, Long modmailThreadId, Member member) {
|
||||
Optional<GuildMessageChannel> textChannelFromServer = channelService.getMessageChannelFromServerOptional(serverId, channelId);
|
||||
if(textChannelFromServer.isPresent()) {
|
||||
GuildMessageChannel guildMessageChannel = textChannelFromServer.get();
|
||||
return self.sendUserReply(guildMessageChannel, modmailThreadId, messageFromUser, member, true);
|
||||
return self.sendUserReply(guildMessageChannel, modmailThreadId, messageFromUser, true);
|
||||
} else {
|
||||
log.warn("Closing mod mail thread {}, because it seems the channel {} in server {} got deleted.", modmailThreadId, channelId, serverId);
|
||||
// in this case there was no text channel on the server associated with the mod mail thread
|
||||
@@ -505,11 +525,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* @param messageChannel The {@link GuildMessageChannel} in which the {@link ModMailThread} is being handled
|
||||
* @param modMailThreadId The id of the modmail thread to which the received {@link Message} is a reply to, can be null, if it is null, its the initial message
|
||||
* @param messageFromUser The received message from the user
|
||||
* @param member The {@link Member} instance from the user the thread is about. It is used as author
|
||||
* @param modMailThreadExists Whether the modmail thread already exists and is persisted.
|
||||
* @return A {@link CompletableFuture} which resolves when the postprocessing of the message is completed (adding read notification, and storing messageIDs)
|
||||
*/
|
||||
public CompletableFuture<Message> sendUserReply(GuildMessageChannel messageChannel, Long modMailThreadId, Message messageFromUser, Member member, boolean modMailThreadExists) {
|
||||
public CompletableFuture<Message> sendUserReply(GuildMessageChannel messageChannel, Long modMailThreadId, Message messageFromUser, boolean modMailThreadExists) {
|
||||
List<CompletableFuture<Member>> subscriberMemberFutures = new ArrayList<>();
|
||||
if(modMailThreadExists) {
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId);
|
||||
@@ -550,7 +569,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
ModMailUserReplyModel modMailUserReplyModel = ModMailUserReplyModel
|
||||
.builder()
|
||||
.postedMessage(messageFromUser)
|
||||
.member(member)
|
||||
.userDisplay(UserDisplay.fromUser(messageFromUser.getAuthor()))
|
||||
.attachedImageUrls(imageUrls)
|
||||
.remainingAttachments(otherAttachments)
|
||||
.subscribers(subscribers)
|
||||
@@ -604,21 +623,16 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CompletableFuture<Void> loadExecutingMemberAndRelay(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, Member targetMember) {
|
||||
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", replyCommandMessage.getId(), targetMember.getId(), modmailThreadId, targetMember.getGuild().getId());
|
||||
public CompletableFuture<Void> loadExecutingMemberAndRelay(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, User user, Guild guild) {
|
||||
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", replyCommandMessage.getId(), user.getId(), modmailThreadId, guild.getId());
|
||||
return memberService.getMemberInServerAsync(replyCommandMessage.getGuild().getIdLong(), replyCommandMessage.getAuthor().getIdLong())
|
||||
.thenCompose(executingMember -> self.relayMessageToDm(modmailThreadId, text, replyCommandMessage, anonymous, targetMember, executingMember));
|
||||
.thenCompose(executingMember -> self.relayMessageToDm(modmailThreadId, text, replyCommandMessage, anonymous, user, executingMember));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, Member targetMember, Member executingMember) {
|
||||
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, User user, Member executingMember) {
|
||||
metricService.incrementCounter(MDOMAIL_THREAD_MESSAGE_SENT);
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getById(modmailThreadId);
|
||||
FullUserInServer fullThreadUser = FullUserInServer
|
||||
.builder()
|
||||
.aUserInAServer(modMailThread.getUser())
|
||||
.member(targetMember)
|
||||
.build();
|
||||
List<String> imageUrls = replyCommandMessage
|
||||
.getAttachments()
|
||||
.stream()
|
||||
@@ -638,7 +652,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
.remainingAttachments(otherAttachments)
|
||||
.attachedImageUrls(imageUrls)
|
||||
.anonymous(anonymous)
|
||||
.threadUser(fullThreadUser);
|
||||
.userDisplay(UserDisplay.fromUser(user));
|
||||
if(anonymous) {
|
||||
log.debug("Message is sent anonymous.");
|
||||
modMailModeratorReplyModelBuilder.moderator(memberService.getBotInGuild(modMailThread.getServer()));
|
||||
@@ -647,7 +661,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY, modMailUserReplyModel, modMailThread.getServer().getId());
|
||||
CompletableFuture<Message> future = messageService.sendMessageToSendToUser(targetMember.getUser(), messageToSend);
|
||||
CompletableFuture<Message> future = messageService.sendMessageToSendToUser(user, messageToSend);
|
||||
CompletableFuture<Message> sameThreadMessageFuture;
|
||||
if(featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, modMailThread.getServer(), ModMailMode.SEPARATE_MESSAGE)) {
|
||||
sameThreadMessageFuture = channelService.sendMessageEmbedToSendToAChannel(messageToSend, modMailThread.getChannel()).get(0);
|
||||
@@ -679,24 +693,24 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
log.info("Archiving thread {} for modmail thread closing.", modMailThread.getChannel().getId());
|
||||
return loadUserAndSendClosingHeader(modMailThread, closingConfig)
|
||||
.thenCompose(unused -> channelService.archiveThreadChannel(threadChannel))
|
||||
.thenCompose(unused -> memberService.getMemberInServerAsync(serverId, userId))
|
||||
.thenAccept(member -> self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), member, undoActions));
|
||||
.thenCompose(unused -> userService.retrieveUserForId(userId))
|
||||
.thenCompose(user -> self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), user, undoActions));
|
||||
} else {
|
||||
if(closingConfig.getLog()) {
|
||||
if(!modMailMessages.isEmpty()) {
|
||||
return modMailMessageService.loadModMailMessages(modMailMessages)
|
||||
.thenAccept(loadedModmailThreadMessages -> self.logMessagesToModMailLog(closingConfig, modMailThreadId, undoActions, loadedModmailThreadMessages, serverId, userId));
|
||||
.thenCompose(loadedModmailThreadMessages -> self.logMessagesToModMailLog(closingConfig, modMailThreadId, undoActions, loadedModmailThreadMessages, serverId, userId));
|
||||
} else {
|
||||
log.info("Modmail thread {} in server {} has no messages. Only logging header.", modMailThreadId, serverId);
|
||||
return loadUserAndSendClosingHeader(modMailThread, closingConfig)
|
||||
.thenAccept(unused -> memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
|
||||
self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), member, undoActions)
|
||||
.thenCompose(unused -> userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenCompose(user ->
|
||||
self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), user, undoActions)
|
||||
));
|
||||
}
|
||||
} else {
|
||||
log.debug("Not logging modmail thread {}.", modMailThreadId);
|
||||
return memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
|
||||
self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), member, undoActions)
|
||||
return userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenCompose(user ->
|
||||
self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), user, undoActions)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -736,8 +750,8 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
undoActions.add(UndoActionInstance.getMessageDeleteAction(message.getGuild().getIdLong(), message.getChannel().getIdLong(), message.getIdLong()));
|
||||
}
|
||||
});
|
||||
return memberService.getMemberInServerAsync(serverId, userId).thenCompose(member ->
|
||||
self.afterSuccessfulLog(modMailThreadId, closingContext.getNotifyUser(), member, undoActions)
|
||||
return userService.retrieveUserForId(userId).thenCompose(user ->
|
||||
self.afterSuccessfulLog(modMailThreadId, closingContext.getNotifyUser(), user, undoActions)
|
||||
).exceptionally(throwable -> {
|
||||
log.warn("Failed to retrieve member for closing the modmail thread. Closing without member information.", throwable);
|
||||
self.afterSuccessfulLog(modMailThreadId, false, null, undoActions);
|
||||
@@ -756,12 +770,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* @param modMailThreadId The ID of the {@link ModMailThread} which is being closed.
|
||||
* @param notifyUser Whether the user should be notified
|
||||
* @param undoActions The list of {@link UndoActionInstance} to execute in case of exceptions
|
||||
* @param modMailThreaduser The {@link Member member} for which the {@link ModMailThread thread} was for
|
||||
* @param modMailThreaduser The {@link User member} for which the {@link ModMailThread thread} was for
|
||||
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
|
||||
* @return A {@link CompletableFuture future} which completes after the messages have been logged
|
||||
*/
|
||||
@Transactional
|
||||
public CompletableFuture<Void> afterSuccessfulLog(Long modMailThreadId, Boolean notifyUser, Member modMailThreaduser, List<UndoActionInstance> undoActions) {
|
||||
public CompletableFuture<Void> afterSuccessfulLog(Long modMailThreadId, Boolean notifyUser, User modMailThreaduser, List<UndoActionInstance> undoActions) {
|
||||
log.debug("Mod mail logging for thread {} has completed. Starting post logging activities.", modMailThreadId);
|
||||
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getByIdOptional(modMailThreadId);
|
||||
if(modMailThreadOpt.isPresent()) {
|
||||
@@ -771,7 +785,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
HashMap<String, String> closingMessage = new HashMap<>();
|
||||
String defaultValue = templateService.renderSimpleTemplate("modmail_closing_user_message_description");
|
||||
closingMessage.put("closingMessage", configService.getStringValue(MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY, modMailThread.getServer().getId(), defaultValue));
|
||||
return messageService.sendEmbedToUser(modMailThreaduser.getUser(), "modmail_closing_user_message", closingMessage).thenAccept(message ->
|
||||
return messageService.sendEmbedToUser(modMailThreaduser, "modmail_closing_user_message", closingMessage).thenCompose(message ->
|
||||
self.deleteChannelAndClose(modMailThreadId, undoActions)
|
||||
).exceptionally(throwable -> {
|
||||
self.deleteChannelAndClose(modMailThreadId, undoActions);
|
||||
@@ -1002,6 +1016,28 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> banUserFromAppealServer(Long mainServerId, Long userId, String reason) {
|
||||
Long configuredAppealServerId = configService.getLongValue(ModMailFeatureConfig.MOD_MAIL_APPEAL_SERVER, mainServerId);
|
||||
Guild appealGuild = guildService.getGuildById(configuredAppealServerId);
|
||||
return banService.banUser(appealGuild, ServerUser.fromId(configuredAppealServerId, userId), Duration.ZERO, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> rejectAppeal(ModMailThread modMailThread, String reason, Member memberPerforming) {
|
||||
ClosingContext context = ClosingContext
|
||||
.builder()
|
||||
.closingMember(memberPerforming)
|
||||
.notifyUser(true)
|
||||
.log(true)
|
||||
.note(reason)
|
||||
.build();
|
||||
Long mainServerId = modMailThread.getServer().getId();
|
||||
Long userToBanId = modMailThread.getUser().getUserReference().getId();
|
||||
return closeModMailThread(modMailThread, context, new ArrayList<>())
|
||||
.thenCompose((nul) -> self.banUserFromAppealServer(mainServerId, userToBanId , reason));
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
metricService.registerCounter(MODMAIL_THREAD_CREATED_COUNTER, "Mod mail threads created");
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<property name="modmailModule" value="(SELECT id FROM module WHERE name = 'modmail')"/>
|
||||
<property name="modmailFeature" value="(SELECT id FROM feature WHERE key = 'modmail')"/>
|
||||
|
||||
<changeSet author="Sheldan" id="modmail_denyModmailAppeal_command">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="denyModmailAppeal"/>
|
||||
<column name="module_id" valueComputed="${modmailModule}"/>
|
||||
<column name="feature_id" valueComputed="${modmailFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<include file="command.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -3,4 +3,5 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<include file="1.0-modmail/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.5.37/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -21,4 +21,11 @@ abstracto.featureModes.threadContainer.enabled=false
|
||||
|
||||
abstracto.featureModes.threadMessage.featureName=modmail
|
||||
abstracto.featureModes.threadMessage.mode=threadMessage
|
||||
abstracto.featureModes.threadMessage.enabled=true
|
||||
abstracto.featureModes.threadMessage.enabled=true
|
||||
|
||||
abstracto.featureModes.modMailAppeals.featureName=modmail
|
||||
abstracto.featureModes.modMailAppeals.mode=modMailAppeals
|
||||
abstracto.featureModes.modMailAppeals.enabled=false
|
||||
|
||||
abstracto.systemConfigs.modMailAppealServer.name=modMailAppealServer
|
||||
abstracto.systemConfigs.modMailAppealServer.longValue=0
|
||||
@@ -1,141 +0,0 @@
|
||||
package dev.sheldan.abstracto.modmail.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.listener.MessageDeletedModel;
|
||||
import dev.sheldan.abstracto.core.service.MemberService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailMessage;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagementService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ModMailMessageDeletedListenerTest {
|
||||
|
||||
@InjectMocks
|
||||
private ModMailMessageDeletedListener testUnit;
|
||||
|
||||
@Mock
|
||||
private ModMailMessageManagementService modMailMessageManagementService;
|
||||
|
||||
@Mock
|
||||
private MessageService messageService;
|
||||
|
||||
@Mock
|
||||
private ModMailMessageDeletedListener self;
|
||||
|
||||
@Mock
|
||||
private MemberService memberService;
|
||||
|
||||
@Mock
|
||||
private CachedMessage deletedMessage;
|
||||
|
||||
@Mock
|
||||
private ModMailMessage modMailMessage;
|
||||
|
||||
@Mock
|
||||
private Member targetMember;
|
||||
|
||||
@Mock
|
||||
private User targetUser;
|
||||
|
||||
@Mock
|
||||
private AServer server;
|
||||
|
||||
@Mock
|
||||
private AChannel channel;
|
||||
|
||||
@Mock
|
||||
private MessageDeletedModel model;
|
||||
|
||||
private static final Long DELETED_MESSAGE_ID = 4L;
|
||||
private static final Long CREATED_MESSAGE_ID_1 = 3L;
|
||||
private static final Long CREATED_MESSAGE_ID_2 = 5L;
|
||||
private static final Long USER_ID = 5L;
|
||||
private static final Long SERVER_ID = 6L;
|
||||
private static final Long CHANNEL_ID = 9L;
|
||||
|
||||
@Test
|
||||
public void testDeleteOutSideOfThread() {
|
||||
when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.empty());
|
||||
when(model.getCachedMessage()).thenReturn(deletedMessage);
|
||||
testUnit.execute(model);
|
||||
verify(memberService, times(0)).getMemberInServerAsync(anyLong(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteNonDuplicatedMessage() {
|
||||
when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
ModMailThread thread = Mockito.mock(ModMailThread.class);
|
||||
AUserInAServer targetUsInAServer = Mockito.mock(AUserInAServer.class);
|
||||
when(thread.getUser()).thenReturn(targetUsInAServer);
|
||||
when(thread.getChannel()).thenReturn(channel);
|
||||
when(thread.getServer()).thenReturn(server);
|
||||
AUser targetAUser = Mockito.mock(AUser.class);
|
||||
when(targetUsInAServer.getUserReference()).thenReturn(targetAUser);
|
||||
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
|
||||
when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID_2);
|
||||
when(targetAUser.getId()).thenReturn(USER_ID);
|
||||
when(modMailMessage.getThreadReference()).thenReturn(thread);
|
||||
when(targetMember.getUser()).thenReturn(targetUser);
|
||||
when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
|
||||
when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(model.getCachedMessage()).thenReturn(deletedMessage);
|
||||
when(model.getServerId()).thenReturn(SERVER_ID);
|
||||
testUnit.execute(model);
|
||||
verify(messageService, times(0)).deleteMessageInChannelInServer(eq(SERVER_ID), anyLong(), any());
|
||||
verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteDuplicatedMessage() {
|
||||
when(deletedMessage.getMessageId()).thenReturn(DELETED_MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
ModMailThread thread = Mockito.mock(ModMailThread.class);
|
||||
AUserInAServer targetUsInAServer = Mockito.mock(AUserInAServer.class);
|
||||
when(thread.getUser()).thenReturn(targetUsInAServer);
|
||||
when(thread.getChannel()).thenReturn(channel);
|
||||
when(thread.getServer()).thenReturn(server);
|
||||
when(server.getId()).thenReturn(SERVER_ID);
|
||||
when(channel.getId()).thenReturn(CHANNEL_ID);
|
||||
AUser targetAUser = Mockito.mock(AUser.class);
|
||||
when(targetUsInAServer.getUserReference()).thenReturn(targetAUser);
|
||||
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID_1);
|
||||
when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID_2);
|
||||
when(targetAUser.getId()).thenReturn(USER_ID);
|
||||
when(modMailMessage.getThreadReference()).thenReturn(thread);
|
||||
when(targetMember.getUser()).thenReturn(targetUser);
|
||||
when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
|
||||
when(messageService.deleteMessageInChannelWithUser(targetUser, CREATED_MESSAGE_ID_2)).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(messageService.deleteMessageInChannelInServer(SERVER_ID, CHANNEL_ID, CREATED_MESSAGE_ID_1)).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(model.getServerId()).thenReturn(SERVER_ID);
|
||||
when(model.getCachedMessage()).thenReturn(deletedMessage);
|
||||
testUnit.execute(model);
|
||||
verify(self, times(1)).removeMessageFromThread(DELETED_MESSAGE_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeMessageFromThread() {
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(DELETED_MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
testUnit.removeMessageFromThread(DELETED_MESSAGE_ID);
|
||||
verify(modMailMessageManagementService, times(1)).deleteMessageFromThread(modMailMessage);
|
||||
}
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
package dev.sheldan.abstracto.modmail.listener;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.config.Parameters;
|
||||
import dev.sheldan.abstracto.core.command.service.CommandRegistry;
|
||||
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.listener.MessageUpdatedModel;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.MemberService;
|
||||
import dev.sheldan.abstracto.core.service.MessageService;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailMessage;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
|
||||
import dev.sheldan.abstracto.modmail.model.template.ModMailModeratorReplyModel;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
|
||||
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
|
||||
import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.*;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static dev.sheldan.abstracto.modmail.listener.ModMailMessageEditedListener.DEFAULT_COMMAND_FOR_MODMAIL_EDIT;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ModMailMessageEditedListenerTest {
|
||||
|
||||
@InjectMocks
|
||||
private ModMailMessageEditedListener testUnit;
|
||||
|
||||
@Mock
|
||||
private ModMailThreadService modMailThreadService;
|
||||
|
||||
@Mock
|
||||
private ModMailMessageManagementService modMailMessageManagementService;
|
||||
|
||||
@Mock
|
||||
private CommandRegistry commandRegistry;
|
||||
|
||||
@Mock
|
||||
private CommandService commandService;
|
||||
|
||||
@Mock
|
||||
private MemberService memberService;
|
||||
|
||||
@Mock
|
||||
private TemplateService templateService;
|
||||
|
||||
@Mock
|
||||
private ChannelService channelService;
|
||||
|
||||
@Mock
|
||||
private MessageService messageService;
|
||||
|
||||
@Mock
|
||||
private ModMailMessageEditedListener self;
|
||||
|
||||
@Mock
|
||||
private CachedMessage messageBefore;
|
||||
|
||||
@Mock
|
||||
private Message messageAfter;
|
||||
|
||||
@Mock
|
||||
private Message loadedMessage;
|
||||
|
||||
@Mock
|
||||
private ModMailMessage modMailMessage;
|
||||
|
||||
@Mock
|
||||
private Parameters parsedParameters;
|
||||
|
||||
@Mock
|
||||
private Member targetMember;
|
||||
|
||||
@Mock
|
||||
private User targetUser;
|
||||
|
||||
@Mock
|
||||
private MessageToSend messageToSend;
|
||||
|
||||
@Mock
|
||||
private Member authorMember;
|
||||
|
||||
@Mock
|
||||
private Guild guild;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<ModMailModeratorReplyModel> replyModelArgumentCaptor;
|
||||
|
||||
@Mock
|
||||
private MessageUpdatedModel model;
|
||||
|
||||
private static final Long CHANNEL_ID = 5L;
|
||||
private static final Long MESSAGE_ID = 6L;
|
||||
private static final Long CREATED_MESSAGE_ID = 10L;
|
||||
private static final String NEW_COMMAND_PART = "editedText";
|
||||
private static final String NEW_PARAM = "param";
|
||||
private static final String NEW_CONTENT = NEW_COMMAND_PART + " " + NEW_PARAM;
|
||||
private static final Long SERVER_ID = 4L;
|
||||
private static final Long USER_ID = 3L;
|
||||
private static final Long AUTHOR_USER_ID = 9L;
|
||||
|
||||
|
||||
@Test
|
||||
public void testEditOutsideModMailThread() {
|
||||
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(false);
|
||||
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
|
||||
when(model.getAfter()).thenReturn(messageAfter);
|
||||
when(model.getBefore()).thenReturn(messageBefore);
|
||||
testUnit.execute(model);
|
||||
verify(modMailMessageManagementService, times(0)).getByMessageIdOptional(anyLong());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEditMessageWithCorrectCommand() {
|
||||
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
|
||||
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
|
||||
when(model.getBefore()).thenReturn(messageBefore);
|
||||
when(model.getAfter()).thenReturn(messageAfter);
|
||||
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.empty());
|
||||
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
|
||||
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
|
||||
when(messageBefore.getServerId()).thenReturn(SERVER_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
ModMailThread thread = Mockito.mock(ModMailThread.class);
|
||||
when(modMailMessage.getThreadReference()).thenReturn(thread);
|
||||
AUserInAServer targetUsInAServer = Mockito.mock(AUserInAServer.class);
|
||||
when(thread.getUser()).thenReturn(targetUsInAServer);
|
||||
AUser targetUser = Mockito.mock(AUser.class);
|
||||
when(targetUsInAServer.getUserReference()).thenReturn(targetUser);
|
||||
when(targetUser.getId()).thenReturn(USER_ID);
|
||||
AUserInAServer authorUserInAServer = Mockito.mock(AUserInAServer.class);
|
||||
when(modMailMessage.getAuthor()).thenReturn(authorUserInAServer);
|
||||
AUser authorUser = Mockito.mock(AUser.class);
|
||||
when(authorUser.getId()).thenReturn(AUTHOR_USER_ID);
|
||||
when(authorUserInAServer.getUserReference()).thenReturn(authorUser);
|
||||
when(messageAfter.getContentStripped()).thenReturn(NEW_CONTENT);
|
||||
when(commandRegistry.getCommandName(NEW_COMMAND_PART, SERVER_ID)).thenReturn(NEW_COMMAND_PART);
|
||||
when(commandService.doesCommandExist(NEW_COMMAND_PART)).thenReturn(true);
|
||||
when(commandService.getParametersForCommand(NEW_COMMAND_PART, messageAfter)).thenReturn(CompletableFuture.completedFuture(parsedParameters));
|
||||
when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
|
||||
when(memberService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
|
||||
when(model.getAfter()).thenReturn(messageAfter);
|
||||
when(model.getBefore()).thenReturn(messageBefore);
|
||||
testUnit.execute(model);
|
||||
verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditMessageWithInCorrectCommand() {
|
||||
when(messageBefore.getChannelId()).thenReturn(CHANNEL_ID);
|
||||
when(messageBefore.getMessageId()).thenReturn(MESSAGE_ID);
|
||||
when(messageBefore.getServerId()).thenReturn(SERVER_ID);
|
||||
when(modMailThreadService.isModMailThread(CHANNEL_ID)).thenReturn(true);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
ModMailThread thread = Mockito.mock(ModMailThread.class);
|
||||
when(modMailMessage.getThreadReference()).thenReturn(thread);
|
||||
AUserInAServer aUserInAServer = Mockito.mock(AUserInAServer.class);
|
||||
when(thread.getUser()).thenReturn(aUserInAServer);
|
||||
AUser user = Mockito.mock(AUser.class);
|
||||
when(aUserInAServer.getUserReference()).thenReturn(user);
|
||||
when(user.getId()).thenReturn(USER_ID);
|
||||
AUserInAServer authorUserInAServer = Mockito.mock(AUserInAServer.class);
|
||||
when(modMailMessage.getAuthor()).thenReturn(authorUserInAServer);
|
||||
AUser authorUser = Mockito.mock(AUser.class);
|
||||
when(authorUser.getId()).thenReturn(AUTHOR_USER_ID);
|
||||
when(authorUserInAServer.getUserReference()).thenReturn(authorUser);
|
||||
when(messageAfter.getContentStripped()).thenReturn(NEW_CONTENT);
|
||||
when(commandRegistry.getCommandName(NEW_COMMAND_PART, SERVER_ID)).thenReturn(NEW_COMMAND_PART);
|
||||
when(commandService.doesCommandExist(NEW_COMMAND_PART)).thenReturn(false);
|
||||
when(commandService.getParametersForCommand(DEFAULT_COMMAND_FOR_MODMAIL_EDIT, messageAfter)).thenReturn(CompletableFuture.completedFuture(parsedParameters));
|
||||
when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(targetMember));
|
||||
when(memberService.getMemberInServerAsync(SERVER_ID, AUTHOR_USER_ID)).thenReturn(CompletableFuture.completedFuture(authorMember));
|
||||
when(model.getAfter()).thenReturn(messageAfter);
|
||||
when(model.getBefore()).thenReturn(messageBefore);
|
||||
testUnit.execute(model);
|
||||
verify(self, times(1)).updateMessageInThread(messageAfter, parsedParameters, targetMember, authorMember);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAnonymousMessageInThreadNotSentToModMailThreadChannel() {
|
||||
when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
when(modMailMessage.getAnonymous()).thenReturn(true);
|
||||
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
|
||||
when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID);
|
||||
ModMailThread thread = Mockito.mock(ModMailThread.class);
|
||||
when(modMailMessage.getThreadReference()).thenReturn(thread);
|
||||
when(targetMember.getUser()).thenReturn(targetUser);
|
||||
when(authorMember.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
|
||||
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture(), eq(SERVER_ID))).thenReturn(messageToSend);
|
||||
testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
|
||||
verify(channelService, times(0)).editMessageInAChannel(eq(messageToSend), any(AChannel.class), anyLong());
|
||||
verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
|
||||
Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAnonymousMessageInThreadAlsoSendToModMailThreadChannel() {
|
||||
when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
when(modMailMessage.getAnonymous()).thenReturn(true);
|
||||
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID);
|
||||
when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID);
|
||||
ModMailThread thread = Mockito.mock(ModMailThread.class);
|
||||
when(modMailMessage.getThreadReference()).thenReturn(thread);
|
||||
when(targetMember.getUser()).thenReturn(targetUser);
|
||||
when(authorMember.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
AChannel channel = Mockito.mock(AChannel.class);
|
||||
when(thread.getChannel()).thenReturn(channel);
|
||||
when(channel.getId()).thenReturn(CHANNEL_ID);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
|
||||
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture(), eq(SERVER_ID))).thenReturn(messageToSend);
|
||||
testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
|
||||
verify(channelService, times(1)).editMessageInAChannel(eq(messageToSend), eq(channel), eq(CREATED_MESSAGE_ID));
|
||||
verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
|
||||
Assert.assertTrue(replyModelArgumentCaptor.getValue().getAnonymous());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateMessageInThreadNotDuplicated() {
|
||||
when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
when(modMailMessage.getAnonymous()).thenReturn(false);
|
||||
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(null);
|
||||
when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID);
|
||||
ModMailThread thread = Mockito.mock(ModMailThread.class);
|
||||
when(modMailMessage.getThreadReference()).thenReturn(thread);
|
||||
when(targetMember.getUser()).thenReturn(targetUser);
|
||||
when(authorMember.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
|
||||
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture(), eq(SERVER_ID))).thenReturn(messageToSend);
|
||||
testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
|
||||
verify(channelService, times(0)).editMessageInAChannel(eq(messageToSend), any(AChannel.class), anyLong());
|
||||
verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
|
||||
Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateMessageInThreadDuplicated() {
|
||||
when(loadedMessage.getIdLong()).thenReturn(MESSAGE_ID);
|
||||
when(modMailMessageManagementService.getByMessageIdOptional(MESSAGE_ID)).thenReturn(Optional.of(modMailMessage));
|
||||
when(modMailMessage.getAnonymous()).thenReturn(false);
|
||||
when(modMailMessage.getCreatedMessageInChannel()).thenReturn(CREATED_MESSAGE_ID);
|
||||
when(modMailMessage.getCreatedMessageInDM()).thenReturn(CREATED_MESSAGE_ID);
|
||||
ModMailThread thread = Mockito.mock(ModMailThread.class);
|
||||
when(modMailMessage.getThreadReference()).thenReturn(thread);
|
||||
when(targetMember.getUser()).thenReturn(targetUser);
|
||||
when(authorMember.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
AChannel channel = Mockito.mock(AChannel.class);
|
||||
when(thread.getChannel()).thenReturn(channel);
|
||||
when(channel.getId()).thenReturn(CHANNEL_ID);
|
||||
when(parsedParameters.getParameters()).thenReturn(Arrays.asList(NEW_PARAM));
|
||||
when(templateService.renderEmbedTemplate(eq(ModMailThreadServiceBean.MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY), replyModelArgumentCaptor.capture(), eq(SERVER_ID))).thenReturn(messageToSend);
|
||||
testUnit.updateMessageInThread(loadedMessage, parsedParameters, targetMember, authorMember);
|
||||
verify(channelService, times(1)).editMessageInAChannel(eq(messageToSend), eq(channel), eq(CREATED_MESSAGE_ID));
|
||||
verify(messageService, times(1)).editMessageInDMChannel(targetUser, messageToSend, CREATED_MESSAGE_ID);
|
||||
Assert.assertFalse(replyModelArgumentCaptor.getValue().getAnonymous());
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>modmail</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
public class ModMailFeatureConfig implements FeatureConfig {
|
||||
|
||||
public static final String MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY = "modMailClosingText";
|
||||
public static final String MOD_MAIL_APPEAL_SERVER = "modMailAppealServer";
|
||||
@Autowired
|
||||
private ModMailFeatureValidator modMailFeatureValidator;
|
||||
|
||||
@@ -34,27 +35,33 @@ public class ModMailFeatureConfig implements FeatureConfig {
|
||||
|
||||
@Override
|
||||
public List<PostTargetEnum> getRequiredPostTargets() {
|
||||
return Arrays.asList(ModMailPostTargets.MOD_MAIL_PING, ModMailPostTargets.MOD_MAIL_LOG, ModMailPostTargets.MOD_MAIL_CONTAINER);
|
||||
return List.of(ModMailPostTargets.MOD_MAIL_PING,
|
||||
ModMailPostTargets.MOD_MAIL_LOG,
|
||||
ModMailPostTargets.MOD_MAIL_CONTAINER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureValidator> getAdditionalFeatureValidators() {
|
||||
return Arrays.asList(modMailFeatureValidator);
|
||||
return List.of(modMailFeatureValidator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRequiredEmotes() {
|
||||
return Arrays.asList("readReaction");
|
||||
return List.of("readReaction");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getAvailableModes() {
|
||||
return Arrays.asList(ModMailMode.LOGGING, ModMailMode.SEPARATE_MESSAGE, ModMailMode.THREAD_CONTAINER);
|
||||
return List.of(ModMailMode.LOGGING,
|
||||
ModMailMode.SEPARATE_MESSAGE,
|
||||
ModMailMode.THREAD_CONTAINER,
|
||||
ModMailMode.MOD_MAIL_APPEALS
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRequiredSystemConfigKeys() {
|
||||
return Arrays.asList(MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY);
|
||||
return List.of(MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY, MOD_MAIL_APPEAL_SERVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,7 +9,10 @@ import lombok.Getter;
|
||||
*/
|
||||
@Getter
|
||||
public enum ModMailMode implements FeatureMode {
|
||||
LOGGING("log"), SEPARATE_MESSAGE("threadMessage"), THREAD_CONTAINER("threadContainer");
|
||||
LOGGING("log"),
|
||||
SEPARATE_MESSAGE("threadMessage"),
|
||||
THREAD_CONTAINER("threadContainer"),
|
||||
MOD_MAIL_APPEALS("modMailAppeals");
|
||||
|
||||
private final String key;
|
||||
|
||||
|
||||
@@ -13,6 +13,5 @@ public class ClosingContext {
|
||||
private Boolean notifyUser;
|
||||
private Boolean log;
|
||||
private Member closingMember;
|
||||
private Channel channel;
|
||||
private String note;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package dev.sheldan.abstracto.modmail.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class ContactNotificationModel {
|
||||
private Member targetMember;
|
||||
private UserDisplay userDisplay;
|
||||
private MessageChannel createdChannel;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.sheldan.abstracto.modmail.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.FullUserInServer;
|
||||
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
@@ -18,10 +18,7 @@ import java.util.Map;
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailModeratorReplyModel {
|
||||
/**
|
||||
* A {@link FullUserInServer} reference representing the user the thread is about. The member attribute is null, if the user left the guild
|
||||
*/
|
||||
private FullUserInServer threadUser;
|
||||
private UserDisplay userDisplay;
|
||||
/**
|
||||
* The staff {@link Member} which replied to the thread, be it anonymously or normal.
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package dev.sheldan.abstracto.modmail.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.FullUserInServer;
|
||||
import dev.sheldan.abstracto.core.models.context.ServerContext;
|
||||
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailRole;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
|
||||
import java.util.List;
|
||||
@@ -24,10 +23,7 @@ public class ModMailNotificationModel extends ServerContext {
|
||||
* The created {@link ModMailThread} which was just created
|
||||
*/
|
||||
private ModMailThread modMailThread;
|
||||
/**
|
||||
* The {@link FullUserInServer} for which this thread is about
|
||||
*/
|
||||
private Member member;
|
||||
private UserDisplay userDisplay;
|
||||
/**
|
||||
* A list of roles which will be notified upon creation of the mod mail thread.
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package dev.sheldan.abstracto.modmail.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
|
||||
import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* This is the model used when a new mod mail thread is opened and a message containing some information about the user
|
||||
@@ -16,16 +14,12 @@ import java.time.Instant;
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailThreaderHeader {
|
||||
/**
|
||||
* A {@link Member} instance to retrieve information from
|
||||
*/
|
||||
private Member member;
|
||||
private UserDisplay userDisplay;
|
||||
/**
|
||||
* The latest {@link ModMailThread}, before the current opened one. This is null if there is no closed mod mail thread
|
||||
* for the user
|
||||
*/
|
||||
private ModMailThread latestModMailThread;
|
||||
private Instant memberJoinDate;
|
||||
/**
|
||||
* The amount of previous mod mail thread the user has.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.modmail.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.display.UserDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -16,10 +17,7 @@ import java.util.Map;
|
||||
@Setter
|
||||
@Builder
|
||||
public class ModMailUserReplyModel {
|
||||
/**
|
||||
* The {@link Member} from which the message is and whose mod mail thread it is
|
||||
*/
|
||||
private Member member;
|
||||
private UserDisplay userDisplay;
|
||||
/**
|
||||
* The {@link Message} which was posted, which contains all the possible information
|
||||
*/
|
||||
|
||||
@@ -22,16 +22,17 @@ public interface ModMailThreadService {
|
||||
* Creates a new mod mail thread for the given user. including: the {@link net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel}
|
||||
* in the appropriate {@link net.dv8tion.jda.api.entities.channel.concrete.Category} and calls the methods responsible for storing
|
||||
* the necessary data in the database, notifying the users and sending messages related to the creation of the {@link ModMailThread}
|
||||
* @param member The {@link AUserInAServer} to create the mod mail thread for
|
||||
* @param user The {@link User} to create the mod mail thread for
|
||||
* @param guild The {@link Guild} in which the mod mail thread should be created in
|
||||
* @param initialMessage The initial message sparking this mod mail thread, null in case it was created by a command
|
||||
* @param userInitiated Whether or not the mod mail thread was initiated by a user
|
||||
* @param undoActions A list of {@link dev.sheldan.abstracto.core.models.UndoAction actions} to be undone in case the operation fails. This list will be filled in the method.
|
||||
* @return A {@link CompletableFuture future} which completes when the modmail thread is set up
|
||||
*/
|
||||
CompletableFuture<MessageChannel> createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions);
|
||||
CompletableFuture<MessageChannel> createModMailThreadForUser(User user, Guild guild, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions);
|
||||
|
||||
CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, MessageChannel feedBackChannel);
|
||||
CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, InteractionHook interactionHook);
|
||||
CompletableFuture<Void> sendContactNotification(User user, MessageChannel createdMessageChannel, MessageChannel feedBackChannel);
|
||||
CompletableFuture<Void> sendContactNotification(User user, MessageChannel createdMessageChannel, InteractionHook interactionHook);
|
||||
|
||||
/**
|
||||
* Changes the configuration value of the category used to create mod mail threads to the given ID.
|
||||
@@ -68,10 +69,11 @@ public interface ModMailThreadService {
|
||||
* @param text The parsed text of the reply
|
||||
* @param message The pure {@link Message} containing the command which caused the reply
|
||||
* @param anonymous Whether or nor the message should be send anonymous
|
||||
* @param targetMember The {@link Member} the {@link ModMailThread} is about.
|
||||
* @param targetUser The {@link User} the {@link ModMailThread} is about.
|
||||
* @param guild The guild the reply is created in
|
||||
* @return A {@link CompletableFuture future} which completes when the message has been relayed to the DM
|
||||
*/
|
||||
CompletableFuture<Void> loadExecutingMemberAndRelay(Long threadId, String text, Message message, boolean anonymous, Member targetMember);
|
||||
CompletableFuture<Void> loadExecutingMemberAndRelay(Long threadId, String text, Message message, boolean anonymous, User targetUser, Guild guild);
|
||||
|
||||
/**
|
||||
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel} associated with the mod mail thread,
|
||||
@@ -98,4 +100,6 @@ public interface ModMailThreadService {
|
||||
|
||||
boolean isModMailThread(AChannel channel);
|
||||
boolean isModMailThread(Long channelId);
|
||||
|
||||
CompletableFuture<Void> rejectAppeal(ModMailThread modMailThread, String reason, Member memberPerforming);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto</groupId>
|
||||
<artifactId>abstracto-application</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>profanity-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>profanity-filter</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>remind</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<changeSet author="Sheldan" id="reminder-resize_text">
|
||||
<modifyDataType columnName="text"
|
||||
newDataType="VARCHAR(4000)"
|
||||
tableName="reminder"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<include file="reminder.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -6,4 +6,5 @@
|
||||
<include file="1.2.10-remind/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.2.12/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.3/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.5.39/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>remind</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>repost-detection</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>repost-detection</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>starboard</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>starboard</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>statistic</artifactId>
|
||||
<version>1.5.36-SNAPSHOT</version>
|
||||
<version>1.5.39</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user