mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-03-06 16:26:31 +00:00
Compare commits
65 Commits
v1.5.36
...
release-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
453378f0b6 | ||
|
|
0e95ddf198 | ||
|
|
90816649e2 | ||
|
|
5b90d429c2 | ||
|
|
7b1774b73e | ||
|
|
618155a464 | ||
|
|
feabe6426e | ||
|
|
2dc21ce996 | ||
|
|
5643a41fd8 | ||
|
|
08d0561998 | ||
|
|
879c1b0173 | ||
|
|
d5bf70f586 | ||
|
|
4525fbc861 | ||
|
|
4671a78ff9 | ||
|
|
c4174562c6 | ||
|
|
bfaa5d6140 | ||
|
|
d2e8398fa4 | ||
|
|
c67209925a | ||
|
|
f3ac7895eb | ||
|
|
6d893e39bb | ||
|
|
94140104de | ||
|
|
6d80423244 | ||
|
|
27040e506a | ||
|
|
3bbf5a2391 | ||
|
|
11cb3b9ee1 | ||
|
|
dccf314e53 | ||
|
|
a0daeee3a1 | ||
|
|
1b7c383ced | ||
|
|
087dd266cc | ||
|
|
beda17f672 | ||
|
|
5c234295aa | ||
|
|
9cfe4bf353 | ||
|
|
75c45541c9 | ||
|
|
11ac33ad4a | ||
|
|
a37a0f87a0 | ||
|
|
69353d32db | ||
|
|
b973c4660c | ||
|
|
34692d22eb | ||
|
|
33268cded6 | ||
|
|
40d66df9b0 | ||
|
|
92508d7a1d | ||
|
|
ccbf6147e9 | ||
|
|
a3545c4af0 | ||
|
|
fa187f8817 | ||
|
|
c39b7ebeec | ||
|
|
5cbad801ff | ||
|
|
826bee1f81 | ||
|
|
99bf9a9be0 | ||
|
|
5b5e4973a7 | ||
|
|
65e956827c | ||
|
|
b258a8bc54 | ||
|
|
9864b7d875 | ||
|
|
27466b7333 | ||
|
|
bfb8969d1f | ||
|
|
0097ff801a | ||
|
|
b6a188c04d | ||
|
|
2fa1adde02 | ||
|
|
cb8b64cc01 | ||
|
|
3b3dd0dbb7 | ||
|
|
388fead2a6 | ||
|
|
336c3d0bd8 | ||
|
|
4991ad8f1c | ||
|
|
c5136a1808 | ||
|
|
446d882eec | ||
|
|
b3e207a967 |
2
.env
2
.env
@@ -1,2 +1,2 @@
|
||||
REGISTRY_PREFIX=harbor.sheldan.dev/abstracto/
|
||||
VERSION=1.5.35
|
||||
VERSION=1.5.50
|
||||
15
.github/workflows/build.yml
vendored
15
.github/workflows/build.yml
vendored
@@ -16,7 +16,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -37,15 +37,4 @@ jobs:
|
||||
- name: Build ui application
|
||||
working-directory: ./ui/experience-tracking
|
||||
run: npm run build
|
||||
- uses: actions/setup-ruby@v1
|
||||
- name: Send Webhook Notification
|
||||
if: always()
|
||||
env:
|
||||
JOB_STATUS: ${{ job.status }}
|
||||
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
|
||||
HOOK_OS_NAME: ${{ runner.os }}
|
||||
WORKFLOW_NAME: ${{ github.workflow }}
|
||||
run: |
|
||||
git clone https://github.com/DiscordHooks/github-actions-discord-webhook.git webhook
|
||||
bash webhook/send.sh $JOB_STATUS $WEBHOOK_URL
|
||||
shell: bash
|
||||
|
||||
|
||||
4
.github/workflows/release_manual.yml
vendored
4
.github/workflows/release_manual.yml
vendored
@@ -5,7 +5,7 @@ permissions:
|
||||
contents: write
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
with:
|
||||
path: .env
|
||||
- name: Build and push Docker containers
|
||||
run: docker-compose build && docker-compose push
|
||||
run: docker compose build && docker compose push
|
||||
env:
|
||||
REGISTRY_PREFIX: ${{ steps.dotenv.outputs.registry_prefix }}
|
||||
VERSION: ${{ steps.dotenv.outputs.version }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,9 +14,7 @@ target/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Sheldan
|
||||
Copyright (c) 2024 Sheldan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ShowAssignableRolePlaceConfig extends AbstractConditionableCommand
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
String name = (String) parameters.get(0);
|
||||
AssignableRolePlaceConfig config = service.getAssignableRolePlaceConfig(commandContext.getGuild(), name);
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ASSIGNABLE_ROLES_CONFIG_POST_TEMPLATE_KEY, config, commandContext.getChannel()))
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(ASSIGNABLE_ROLES_CONFIG_POST_TEMPLATE_KEY, config, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ShowAssignableRolePlaces extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
AssignablePlaceOverview model = service.getAssignableRolePlaceOverview(commandContext.getGuild());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.5.36</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public class Choose extends AbstractConditionableCommand {
|
||||
.builder()
|
||||
.chosenValue(choice)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(CHOOSE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(CHOOSE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public class Mock extends AbstractConditionableCommand {
|
||||
.originalText(messageText)
|
||||
.mockingText(mockingText)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(MOCK_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(MOCK_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ public class PressFCommand extends AbstractConditionableCommand {
|
||||
Long defaultDurationSeconds = configService.getLongValueOrConfigDefault(PRESS_F_DEFAULT_DURATION_SECONDS, commandContext.getGuild().getIdLong());
|
||||
Duration duration = Duration.ofSeconds(defaultDurationSeconds);
|
||||
PressFPromptModel pressFModel = entertainmentService.getPressFModel(text);
|
||||
List<CompletableFuture<Message>> messages = channelService.sendEmbedTemplateInMessageChannelList(RESPONSE_TEMPLATE, pressFModel, commandContext.getChannel());
|
||||
List<CompletableFuture<Message>> messages = channelService.sendEmbedTemplateInMessageChannel(RESPONSE_TEMPLATE, pressFModel, commandContext.getChannel());
|
||||
return FutureUtils.toSingleFutureGeneric(messages)
|
||||
.thenAccept(unused -> entertainmentService.persistPressF(text, duration, commandContext.getAuthor(),
|
||||
pressFModel.getPressFComponentId(), commandContext.getChannel(), messages.get(0).join().getIdLong()))
|
||||
|
||||
@@ -69,7 +69,7 @@ public class Roll extends AbstractConditionableCommand {
|
||||
.builder()
|
||||
.rolled(rolled)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ROLL_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(ROLL_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ public class Roulette extends AbstractConditionableCommand {
|
||||
.builder()
|
||||
.result(rouletteResult)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ROULETTE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(ROULETTE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public class TransferCredits extends AbstractConditionableCommand {
|
||||
.targetMember(MemberDisplay.fromMember(targetMember))
|
||||
.credits(amount)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(TRANSFER_CREDITS_RESPONSE, responseModel, commandContext.getChannel()))
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(TRANSFER_CREDITS_RESPONSE, responseModel, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public class Mines extends AbstractConditionableCommand {
|
||||
board.setUserId(event.getMember().getIdLong());
|
||||
board.setServerId(serverId);
|
||||
board.setCredits(credit);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MINE_BOARD_TEMPLATE_KEY, board);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MINE_BOARD_TEMPLATE_KEY, board, serverId);
|
||||
return interactionService.replyMessageToSend(messageToSend, event)
|
||||
.thenCompose(interactionHook -> interactionHook.retrieveOriginal().submit())
|
||||
.thenApply(message -> {
|
||||
@@ -151,7 +151,7 @@ public class Mines extends AbstractConditionableCommand {
|
||||
board.setUserId(commandContext.getAuthor().getIdLong());
|
||||
board.setServerId(serverId);
|
||||
board.setCredits(credit);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MINE_BOARD_TEMPLATE_KEY, board);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MINE_BOARD_TEMPLATE_KEY, board, serverId);
|
||||
List<CompletableFuture<Message>> futures = channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel());
|
||||
return FutureUtils.toSingleFutureGeneric(futures)
|
||||
.thenAccept(unused -> gameService.persistMineBoardMessage(board, futures.get(0).join()))
|
||||
|
||||
@@ -54,7 +54,7 @@ public class MinesButtonClickedListener implements ButtonClickedListener {
|
||||
}
|
||||
gameService.uncoverBoard(mineBoard);
|
||||
}
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(Mines.MINE_BOARD_TEMPLATE_KEY, mineBoard);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(Mines.MINE_BOARD_TEMPLATE_KEY, mineBoard, model.getServerId());
|
||||
interactionService.editOriginal(messageToSend, model.getEvent().getHook()).thenAccept(message -> {
|
||||
gameService.updateMineBoard(mineBoard);
|
||||
log.info("Updated original mineboard for board {}.", mineBoard.getBoardId());
|
||||
|
||||
@@ -105,7 +105,9 @@ public class EntertainmentServiceBean implements EntertainmentService {
|
||||
|
||||
@Override
|
||||
public Integer getLoveCalcValue(String firstPart, String secondPart) {
|
||||
return secureRandom.nextInt(100);
|
||||
String fullInput = firstPart.toLowerCase() + secondPart.toLowerCase();
|
||||
Random random = new Random(fullInput.hashCode());
|
||||
return random.nextInt(100);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -191,8 +193,8 @@ public class EntertainmentServiceBean implements EntertainmentService {
|
||||
.text(pressF.getText())
|
||||
.messageId(pressF.getMessageId())
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PRESS_F_RESULT_TEMPLATE_KEY, model);
|
||||
Long serverId = pressF.getServer().getId();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PRESS_F_RESULT_TEMPLATE_KEY, model, serverId);
|
||||
Long channelId = pressF.getPressFChannel().getId();
|
||||
Long messageId = pressF.getMessageId();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageEmbedToSendToAChannel(messageToSend, pressF.getPressFChannel()))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.model.api.UserExperienceDisplay;
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceRole;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.service.ExperienceLevelService;
|
||||
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@@ -37,6 +38,9 @@ public class LeaderboardController {
|
||||
@Autowired
|
||||
private GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
private ExperienceLevelService experienceLevelService;
|
||||
|
||||
@GetMapping(value = "/leaderboards/{serverId}", produces = "application/json")
|
||||
public Page<UserExperienceDisplay> getLeaderboard(@PathVariable("serverId") Long serverId,
|
||||
@PageableDefault(value = 25, page = 0)
|
||||
@@ -55,6 +59,8 @@ public class LeaderboardController {
|
||||
AExperienceRole experienceRole = aUserExperience.getCurrentExperienceRole();
|
||||
UserDisplay userDisplay = null;
|
||||
RoleDisplay roleDisplay = null;
|
||||
Long experienceNeededToNextLevel = experienceLevelService.calculateExperienceToNextLevel(aUserExperience.getCurrentLevel().getLevel(), aUserExperience.getExperience());
|
||||
Long nextLevelExperience = experienceLevelService.calculateNextLevel(aUserExperience.getCurrentLevel().getLevel()).getExperienceNeeded();
|
||||
if(experienceRole != null) {
|
||||
Role role = guild.getRoleById(experienceRole.getRole().getId());
|
||||
if(role != null) {
|
||||
@@ -66,6 +72,9 @@ public class LeaderboardController {
|
||||
if(member != null) {
|
||||
userDisplay = UserDisplay.fromMember(member);
|
||||
}
|
||||
Long currentExpNeeded = aUserExperience.getCurrentLevel().getExperienceNeeded();
|
||||
Long experienceWithinLevel = aUserExperience.getExperience() - currentExpNeeded;
|
||||
Long experienceNeededForCurrentLevel = nextLevelExperience - currentExpNeeded;
|
||||
return UserExperienceDisplay
|
||||
.builder()
|
||||
.id(String.valueOf(userId))
|
||||
@@ -73,6 +82,11 @@ public class LeaderboardController {
|
||||
.level(aUserExperience.getLevelOrDefault())
|
||||
.rank((int) pageable.getOffset() + page.getContent().indexOf(aUserExperience) + 1)
|
||||
.experience(aUserExperience.getExperience())
|
||||
.experienceToNextLevel(experienceNeededToNextLevel)
|
||||
.currentLevelExperienceNeeded(experienceNeededForCurrentLevel)
|
||||
.experienceOnCurrentLevel(experienceWithinLevel)
|
||||
.percentage(((float) experienceWithinLevel / experienceNeededForCurrentLevel) * 100)
|
||||
.nextLevelExperienceNeeded(nextLevelExperience)
|
||||
.role(roleDisplay)
|
||||
.member(userDisplay)
|
||||
.build();
|
||||
|
||||
@@ -107,13 +107,13 @@ public class Rank extends AbstractConditionableCommand {
|
||||
Long currentExpNeeded = experienceObj.getCurrentLevel().getExperienceNeeded();
|
||||
Long experienceNeededToNextLevel = experienceLevelService.calculateExperienceToNextLevel(experienceObj.getCurrentLevel().getLevel(), experienceObj.getExperience());
|
||||
Long nextLevelExperience = experienceLevelService.calculateNextLevel(experienceObj.getCurrentLevel().getLevel()).getExperienceNeeded();
|
||||
Long levelExperience = nextLevelExperience - currentExpNeeded;
|
||||
Long inLevelExperience = experienceObj.getExperience() - currentExpNeeded;
|
||||
Long experienceNeededForCurrentLevel = nextLevelExperience - currentExpNeeded;
|
||||
Long experienceWithinLevel = experienceObj.getExperience() - currentExpNeeded;
|
||||
rankModel.setExperienceForCurrentLevel(currentExpNeeded);
|
||||
rankModel.setCurrentLevelPercentage(((float) inLevelExperience / levelExperience) * 100);
|
||||
rankModel.setLevelExperience(levelExperience);
|
||||
rankModel.setCurrentLevelPercentage(((float) experienceWithinLevel / experienceNeededForCurrentLevel) * 100);
|
||||
rankModel.setLevelExperience(experienceNeededForCurrentLevel);
|
||||
rankModel.setExperienceToNextLevel(experienceNeededToNextLevel);
|
||||
rankModel.setInLevelExperience(inLevelExperience);
|
||||
rankModel.setInLevelExperience(experienceWithinLevel);
|
||||
rankModel.setNextLevelExperience(nextLevelExperience);
|
||||
return templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel, toRender.getGuild().getIdLong());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -16,4 +16,9 @@ public class UserExperienceDisplay {
|
||||
private Long experience;
|
||||
private Long messages;
|
||||
private RoleDisplay role;
|
||||
private Long experienceToNextLevel;
|
||||
private Long experienceOnCurrentLevel;
|
||||
private Long currentLevelExperienceNeeded;
|
||||
private Float percentage;
|
||||
private Long nextLevelExperienceNeeded;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -361,7 +361,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
.newRole(oldRoleId != null ? RoleDisplay.fromRole(oldRoleId) : null)
|
||||
.newRole(newRoleId != null ? RoleDisplay.fromRole(newRoleId) : null)
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("experience_level_up_notification", model);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("experience_level_up_notification", model, serverId);
|
||||
FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, message.getChannel())).thenAccept(unused -> {
|
||||
log.info("Sent level up notification to user {} in server {} in channel {}.", member.getIdLong(), serverId, message.getChannel().getIdLong());
|
||||
}).exceptionally(throwable -> {
|
||||
@@ -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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>giveaway-impl</artifactId>
|
||||
|
||||
@@ -130,7 +130,7 @@ public class GiveawayServiceBean implements GiveawayService {
|
||||
giveawayMessageModel.setJoinedUserCount(giveaway.getParticipants().size() + 1L);
|
||||
Long giveawayId = giveaway.getGiveawayId().getId();
|
||||
log.info("Adding giveaway participating of user {} to giveaway {} in server {}.", member.getIdLong(), giveawayId, member.getGuild().getIdLong());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel, member.getGuild().getIdLong());
|
||||
return channelService.editEmbedMessageInAChannel(messageToSend.getEmbeds().get(0), messageChannel, giveaway.getMessageId())
|
||||
.thenAccept(message -> {
|
||||
self.persistAddedParticipant(member, giveawayId);
|
||||
@@ -183,13 +183,13 @@ public class GiveawayServiceBean implements GiveawayService {
|
||||
.winners(winnerDisplays)
|
||||
.build();
|
||||
log.info("Sending result message for giveaway {} in server {}.", giveawayId, serverId);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(GIVEAWAY_RESULT_MESSAGE_TEMPLATE_KEY, resultModel);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(GIVEAWAY_RESULT_MESSAGE_TEMPLATE_KEY, resultModel, serverId);
|
||||
List<CompletableFuture<Message>> resultFutures = channelService.sendMessageEmbedToSendToAChannel(messageToSend, giveaway.getGiveawayChannel());
|
||||
|
||||
GiveawayMessageModel giveawayMessageModel = GiveawayMessageModel.fromGiveaway(giveaway);
|
||||
giveawayMessageModel.setWinners(winnerDisplays);
|
||||
giveawayMessageModel.setEnded(true);
|
||||
MessageToSend giveawayMessageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel);
|
||||
MessageToSend giveawayMessageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel, serverId);
|
||||
log.info("Updating original giveaway message for giveaway {} in server {}.", giveawayId, serverId);
|
||||
GuildMessageChannel messageChannel = channelService.getMessageChannelFromServer(giveaway.getServer().getId(), giveaway.getGiveawayChannel().getId());
|
||||
CompletableFuture<Message> giveawayUpdateFuture = channelService.editMessageInAChannelFuture(giveawayMessageToSend, messageChannel, giveaway.getMessageId());
|
||||
@@ -208,7 +208,7 @@ public class GiveawayServiceBean implements GiveawayService {
|
||||
GiveawayMessageModel giveawayMessageModel = GiveawayMessageModel.fromGiveaway(giveaway);
|
||||
giveawayMessageModel.setCancelled(true);
|
||||
schedulerService.stopTrigger(giveaway.getReminderTriggerKey());
|
||||
MessageToSend giveawayMessageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel);
|
||||
MessageToSend giveawayMessageToSend = templateService.renderEmbedTemplate(GIVEAWAY_MESSAGE_TEMPLATE_KEY, giveawayMessageModel, serverId);
|
||||
|
||||
GuildMessageChannel messageChannel = channelService.getMessageChannelFromServer(giveaway.getServer().getId(), giveaway.getGiveawayChannel().getId());
|
||||
log.debug("Updating original giveaway message to consider cancellation for giveaway {} in server {}.", giveawayId, serverId);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>giveaway</artifactId>
|
||||
<version>1.5.36</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>giveaway</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>image-generation</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36</version>
|
||||
<version>1.5.51-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>image-generation-impl</artifactId>
|
||||
|
||||
@@ -58,7 +58,7 @@ public class AmongusText extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
String text = (String) commandContext.getParameters().getParameters().get(0);
|
||||
File amongusTextImage = imageGenerationService.getAmongusTextImage(text);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(AMONGUS_TEXT_EMBED_TEMPLATE_KEY, new Object());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(AMONGUS_TEXT_EMBED_TEMPLATE_KEY, new Object(), commandContext.getGuild().getIdLong());
|
||||
// template support does not support binary files
|
||||
AttachedFile file = AttachedFile
|
||||
.builder()
|
||||
@@ -76,7 +76,7 @@ public class AmongusText extends AbstractConditionableCommand {
|
||||
event.deferReply().queue();
|
||||
String text = slashCommandParameterService.getCommandOption(TEXT_PARAMETER_KEY, event, String.class);
|
||||
File amongusTextImage = imageGenerationService.getAmongusTextImage(text);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(AMONGUS_TEXT_EMBED_TEMPLATE_KEY, new Object());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(AMONGUS_TEXT_EMBED_TEMPLATE_KEY, new Object(), event.getGuild().getIdLong());
|
||||
// template support does not support binary files
|
||||
AttachedFile file = AttachedFile
|
||||
.builder()
|
||||
|
||||
@@ -76,7 +76,7 @@ public class Bonk extends AbstractConditionableCommand {
|
||||
}
|
||||
}
|
||||
File bonkGifFile = imageGenerationService.getBonkGif(member.getEffectiveAvatar().getUrl(imageSize));
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object(), commandContext.getGuild().getIdLong());
|
||||
// template support does not support binary files
|
||||
AttachedFile file = AttachedFile
|
||||
.builder()
|
||||
@@ -99,7 +99,7 @@ public class Bonk extends AbstractConditionableCommand {
|
||||
targetMember = event.getMember();
|
||||
}
|
||||
File bonkGifFile = imageGenerationService.getBonkGif(targetMember.getEffectiveAvatar().getUrl(imageSize));
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object(), event.getGuild().getIdLong());
|
||||
// template support does not support binary files
|
||||
AttachedFile file = AttachedFile
|
||||
.builder()
|
||||
|
||||
@@ -76,7 +76,7 @@ public class Pat extends AbstractConditionableCommand {
|
||||
}
|
||||
}
|
||||
File patGifFile = imageGenerationService.getPatGif(member.getEffectiveAvatar().getUrl(imageSize));
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PAT_EMBED_TEMPLATE_KEY, new Object());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PAT_EMBED_TEMPLATE_KEY, new Object(), commandContext.getGuild().getIdLong());
|
||||
// template support does not support binary files
|
||||
AttachedFile file = AttachedFile
|
||||
.builder()
|
||||
@@ -99,7 +99,7 @@ public class Pat extends AbstractConditionableCommand {
|
||||
targetMember = event.getMember();
|
||||
}
|
||||
File patGifFile = imageGenerationService.getPatGif(targetMember.getEffectiveAvatar().getUrl(imageSize));
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PAT_EMBED_TEMPLATE_KEY, new Object());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PAT_EMBED_TEMPLATE_KEY, new Object(), event.getGuild().getIdLong());
|
||||
// template support does not support binary files
|
||||
AttachedFile file = AttachedFile
|
||||
.builder()
|
||||
|
||||
@@ -68,7 +68,7 @@ public class Triggered extends AbstractConditionableCommand {
|
||||
member = (Member) parameters.get(0);
|
||||
}
|
||||
File triggeredGifFile = imageGenerationService.getTriggeredGif(member.getEffectiveAvatar().getUrl(imageSize));
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(TRIGGERED_EMBED_TEMPLATE_KEY, new Object());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(TRIGGERED_EMBED_TEMPLATE_KEY, new Object(), commandContext.getGuild().getIdLong());
|
||||
// template support does not support binary files
|
||||
AttachedFile file = AttachedFile
|
||||
.builder()
|
||||
@@ -91,7 +91,7 @@ public class Triggered extends AbstractConditionableCommand {
|
||||
targetMember = event.getMember();
|
||||
}
|
||||
File triggeredGifFile = imageGenerationService.getTriggeredGif(targetMember.getEffectiveAvatar().getUrl(imageSize));
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(TRIGGERED_EMBED_TEMPLATE_KEY, new Object());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(TRIGGERED_EMBED_TEMPLATE_KEY, new Object(), event.getGuild().getIdLong());
|
||||
// template support does not support binary files
|
||||
AttachedFile file = AttachedFile
|
||||
.builder()
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>image-generation</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.36</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public class MyWarnings extends AbstractConditionableCommand {
|
||||
.totalWarnCount(totalWarnCount)
|
||||
.currentWarnCount(currentWarnCount)
|
||||
.build();
|
||||
channelService.sendEmbedTemplateInTextChannelList(MY_WARNINGS_RESPONSE_EMBED_TEMPLATE, model, commandContext.getChannel());
|
||||
channelService.sendEmbedTemplateInMessageChannel(MY_WARNINGS_RESPONSE_EMBED_TEMPLATE, model, commandContext.getChannel());
|
||||
return CommandResult.fromIgnored();
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ public class UserNotes extends AbstractConditionableCommand {
|
||||
CompletableFuture<List<NoteEntryModel>> listCompletableFuture = userNotesConverter.fromNotes(userNotes);
|
||||
return listCompletableFuture.thenCompose(noteEntryModels -> {
|
||||
model.setUserNotes(noteEntryModels);
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(USER_NOTES_RESPONSE_TEMPLATE, model, commandContext.getChannel()))
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(USER_NOTES_RESPONSE_TEMPLATE, model, commandContext.getChannel()))
|
||||
.thenApply(aVoid -> CommandResult.fromIgnored());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ public class BanModerationActionModalListener implements ModalInteractionListene
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if(StringUtils.isBlank(tempReason)) {
|
||||
reason = templateService.renderSimpleTemplate(DEFAULT_BAN_REASON_TEMPLATE_KEY);
|
||||
reason = templateService.renderSimpleTemplate(DEFAULT_BAN_REASON_TEMPLATE_KEY, model.getServerId());
|
||||
} else {
|
||||
reason = tempReason;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class HoneyPotRoleAddedListener implements RoleAddedListener {
|
||||
.memberDisplay(MemberDisplay.fromMember(model.getTargetMember()))
|
||||
.roleDisplay(RoleDisplay.fromRole(model.getRole()))
|
||||
.build();
|
||||
String banReason = templateService.renderTemplate(HONEYPOT_BAN_REASON_TEMPLATE, reasonModel);
|
||||
String banReason = templateService.renderTemplate(HONEYPOT_BAN_REASON_TEMPLATE, reasonModel, model.getServerId());
|
||||
banService.banUserWithNotification(model.getTargetUser(), banReason, ServerUser.fromMember(model.getTargetMember().getGuild().getSelfMember()),
|
||||
model.getTargetMember().getGuild(), Duration.ofDays(7)).thenAccept(banResult -> {
|
||||
log.info("Banned user {} in guild {} due to role {}.", model.getTargetUser().getUserId(), model.getTargetUser().getServerId(), model.getRoleId());
|
||||
|
||||
@@ -53,7 +53,7 @@ public class MyWarningsTest {
|
||||
Long totalWarnCount = 10L;
|
||||
when(warnManagementService.getTotalWarnsForUser(aUserInAServer)).thenReturn(totalWarnCount);
|
||||
CommandResult result = testUnit.execute(noParameter);
|
||||
verify(channelService, times(1)).sendEmbedTemplateInTextChannelList(eq(MyWarnings.MY_WARNINGS_RESPONSE_EMBED_TEMPLATE), argumentCaptor.capture(), eq(noParameter.getChannel()));
|
||||
verify(channelService, times(1)).sendEmbedTemplateInMessageChannel(eq(MyWarnings.MY_WARNINGS_RESPONSE_EMBED_TEMPLATE), argumentCaptor.capture(), eq(noParameter.getChannel()));
|
||||
CommandTestUtilities.checkSuccessfulCompletion(result);
|
||||
MyWarningsModel usedModel = argumentCaptor.getValue();
|
||||
Assert.assertEquals(activeWarnCount, usedModel.getCurrentWarnCount());
|
||||
|
||||
@@ -67,7 +67,7 @@ public class UserNotesTest {
|
||||
CompletableFuture<List<NoteEntryModel>> convertedNotes = CompletableFuture.completedFuture(Arrays.asList(firstConvertedNote, secondConvertedNote));
|
||||
when(userNotesConverter.fromNotes(userNotes)).thenReturn(convertedNotes);
|
||||
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);
|
||||
verify(channelService, times(1)).sendEmbedTemplateInTextChannelList(eq(UserNotes.USER_NOTES_RESPONSE_TEMPLATE), captor.capture(), eq(parameters.getChannel()));
|
||||
verify(channelService, times(1)).sendEmbedTemplateInMessageChannel(eq(UserNotes.USER_NOTES_RESPONSE_TEMPLATE), captor.capture(), eq(parameters.getChannel()));
|
||||
ListNotesModel usedModel = captor.getValue();
|
||||
List<NoteEntryModel> notes = convertedNotes.join();
|
||||
Assert.assertEquals(notes.size(), usedModel.getUserNotes().size());
|
||||
@@ -96,7 +96,7 @@ public class UserNotesTest {
|
||||
when(userNotesConverter.fromNotes(userNotes)).thenReturn(convertedNotes);
|
||||
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);
|
||||
List<NoteEntryModel> notes = convertedNotes.join();
|
||||
verify(channelService, times(1)).sendEmbedTemplateInTextChannelList(eq(UserNotes.USER_NOTES_RESPONSE_TEMPLATE), captor.capture(), eq(parameters.getChannel()));
|
||||
verify(channelService, times(1)).sendEmbedTemplateInMessageChannel(eq(UserNotes.USER_NOTES_RESPONSE_TEMPLATE), captor.capture(), eq(parameters.getChannel()));
|
||||
ListNotesModel usedModel = captor.getValue();
|
||||
Assert.assertEquals(notes.size(), usedModel.getUserNotes().size());
|
||||
for (int i = 0; i < usedModel.getUserNotes().size(); i++) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation</artifactId>
|
||||
<version>1.5.36</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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</version>
|
||||
<version>1.5.51-SNAPSHOT</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());
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ public class Close extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// the default value of the note is configurable via template
|
||||
String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate(MODMAIL_CLOSE_DEFAULT_NOTE_TEMPLATE_KEY, new Object());
|
||||
String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate(MODMAIL_CLOSE_DEFAULT_NOTE_TEMPLATE_KEY, new Object(), commandContext.getGuild()
|
||||
.getIdLong());
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(commandContext.getChannel().getIdLong());
|
||||
if(ModMailThreadState.CLOSED.equals(modMailThread.getState()) || ModMailThreadState.CLOSING.equals(modMailThread.getState())) {
|
||||
throw new ModMailThreadClosedException();
|
||||
@@ -81,7 +82,6 @@ public class Close extends AbstractConditionableCommand {
|
||||
.builder()
|
||||
.closingMember(commandContext.getAuthor())
|
||||
.notifyUser(true)
|
||||
.channel(commandContext.getChannel())
|
||||
.log(true)
|
||||
.note(note)
|
||||
.build();
|
||||
@@ -112,19 +112,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();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@ public class CloseSilently extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// default note text is configurable via template, because the note is optional
|
||||
String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object());
|
||||
String note = parameters.size() == 1 ? (String) parameters.get(0) : templateService.renderTemplate("modmail_close_default_note", new Object(), commandContext.getGuild()
|
||||
.getIdLong());
|
||||
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(commandContext.getChannel().getIdLong());
|
||||
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";
|
||||
@@ -84,27 +85,24 @@ public class Contact extends AbstractConditionableCommand {
|
||||
.existingModMailThread(existingThread)
|
||||
.executingMemberDisplay(MemberNameDisplay.fromMember(targetUser))
|
||||
.build();
|
||||
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInTextChannelList(MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE, model, commandContext.getChannel());
|
||||
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInMessageChannel(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(), false)
|
||||
.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<>(), false);
|
||||
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,20 @@ 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());
|
||||
boolean appeal = chosenServer.getAppealModmail() != null && chosenServer.getAppealModmail();
|
||||
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, appeal);
|
||||
} 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, boolean appeal) {
|
||||
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, appeal);
|
||||
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, appeal)
|
||||
.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, appeal)
|
||||
.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));
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannel(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,42 +259,43 @@ 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
|
||||
* @param undoActions The list of actions to undo, in case an exception occurs
|
||||
* @param appeal Whether the modmail thread is for the purpose of an appeal
|
||||
* @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, boolean appeal) {
|
||||
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, appeal);
|
||||
} 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(), appeal);
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void setupModMailThreadInDB(Message initialMessage, GuildMessageChannel channel, Member member, Message sendMessage) {
|
||||
public void setupModMailThreadInDB(Message initialMessage, GuildMessageChannel channel, User user, Message sendMessage, boolean appeal) {
|
||||
log.info("Persisting info about modmail thread {} in database.", channel.getIdLong());
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
ModMailThread thread = createThreadObject(channel, aUserInAServer);
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(channel.getGuild().getIdLong(), user.getIdLong());
|
||||
ModMailThread thread = createThreadObject(channel, aUserInAServer, appeal);
|
||||
if(initialMessage != null) {
|
||||
log.debug("Adding initial message {} to modmail thread in channel {}.", initialMessage.getId(), channel.getId());
|
||||
modMailMessageManagementService.addMessageToThread(thread, null, sendMessage, initialMessage, aUserInAServer, false, false);
|
||||
@@ -302,19 +304,20 @@ 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
|
||||
* @param appeal Whether the modmail thread is for the purpose of an appeal
|
||||
* @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, boolean appeal) {
|
||||
Long serverId = channel.getGuild().getIdLong();
|
||||
MessageToSend messageToSend = getModmailNotificationMessageToSend(user, channel, serverId, true, appeal);
|
||||
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, boolean appeal) {
|
||||
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,11 +325,12 @@ 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)
|
||||
.appeal(appeal)
|
||||
.channel(channel)
|
||||
.build();
|
||||
return templateService.renderEmbedTemplate("modmail_notification_message", modMailNotificationModel, serverId);
|
||||
@@ -336,14 +340,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
* Creates the instance of the {@link ModMailThread} in the database.
|
||||
* @param channel The {@link GuildMessageChannel} in which the {@link ModMailThread} is being done
|
||||
* @param user The {@link AUserInAServer} which the thread is about
|
||||
* @param appeal Whether the modmail thread is for the purpose of an appeal
|
||||
* @return The created instance of {@link ModMailThread}
|
||||
*/
|
||||
public ModMailThread createThreadObject(GuildMessageChannel channel, AUserInAServer user) {
|
||||
public ModMailThread createThreadObject(GuildMessageChannel channel, AUserInAServer user, boolean appeal) {
|
||||
log.info("Creating database objects related to modmail thread in channel {} and about user {} in server {}.", channel.getIdLong(), user.getUserReference().getId(), channel.getGuild().getId());
|
||||
boolean useThreads = featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, channel.getGuild().getIdLong(), ModMailMode.THREAD_CONTAINER);
|
||||
AChannel aChannel = channelManagementService.createChannel(channel.getIdLong(), useThreads ? AChannelType.PUBLIC_THREAD : AChannelType.TEXT, user.getServerReference());
|
||||
log.info("Creating mod mail thread in channel {} with db channel {}", channel.getIdLong(), aChannel.getId());
|
||||
return modMailThreadManagementService.createModMailThread(user, aChannel);
|
||||
return modMailThreadManagementService.createModMailThread(user, aChannel, appeal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -367,75 +372,108 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
AServer server = serverManagementService.loadServer(guild);
|
||||
servers.add(server);
|
||||
});
|
||||
if(!servers.isEmpty()) {
|
||||
log.info("There are {} shared servers between user and the bot.", servers.size());
|
||||
List<ServerChoice> availableGuilds = new ArrayList<>();
|
||||
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();
|
||||
ServerChoice serverChoice = ServerChoice
|
||||
.builder()
|
||||
.serverId(guild.getGuild().getIdLong())
|
||||
.serverName(guild.getGuild().getName())
|
||||
.build();
|
||||
availableGuilds.add(serverChoice);
|
||||
|
||||
if(servers.isEmpty()) {
|
||||
log.warn("User {} which was not known in any of the servers tried to contact the bot.", user.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
boolean possibleForModmail = featureFlagService.isFeatureEnabled(modMailFeatureConfig, server);
|
||||
if (possibleForModmail) {
|
||||
Guild guild = guildService.getGuildById(server.getId());
|
||||
ServerChoice serverChoice = ServerChoice
|
||||
.builder()
|
||||
.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 && !alreadyConsideredServers.contains(potentialMainServer)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
log.info("There were {} shared servers found which have modmail enabled.", availableGuilds.size());
|
||||
// if more than 1 server is available, show a choice dialog
|
||||
ArrayList<UndoActionInstance> undoActions = new ArrayList<>();
|
||||
if(availableGuilds.size() > 1) {
|
||||
Map<String, ServerChoice> choices = new HashMap<>();
|
||||
ServerChoices serverChoices = ServerChoices
|
||||
if(possibleForModmail) {
|
||||
Guild guild = guildService.getGuildById(actualServerId);
|
||||
ServerChoice serverChoice = ServerChoice
|
||||
.builder()
|
||||
.commonGuilds(choices)
|
||||
.userId(initialMessage.getAuthor().getIdLong())
|
||||
.messageId(initialMessage.getIdLong())
|
||||
.serverId(guild.getIdLong())
|
||||
.serverName(guild.getName())
|
||||
.appealModmail(true)
|
||||
.build();
|
||||
availableGuilds.forEach(serverChoice -> choices.put(componentService.generateComponentId(), serverChoice));
|
||||
ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel
|
||||
.builder()
|
||||
.choices(serverChoices)
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_modal_server_choice", modMailServerChooserModel);
|
||||
FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, initialMessage.getChannel()))
|
||||
.thenAccept(unused -> self.persistInitialCallbacks(serverChoices))
|
||||
.exceptionally(throwable -> {
|
||||
log.error("Failed to setup prompt message correctly", throwable);
|
||||
undoActionService.performActions(undoActions);
|
||||
return null;
|
||||
});
|
||||
log.debug("Displaying server choice message for user {} in channel {}.", user.getId(), initialMessage.getChannel().getId());
|
||||
} else if(availableGuilds.size() == 1) {
|
||||
// if exactly one server is available, open the thread directly
|
||||
Long chosenServerId = availableGuilds.get(0).getServerId();
|
||||
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;
|
||||
});
|
||||
} else {
|
||||
log.info("No server available to open a modmail thread in.");
|
||||
// in case there is no server available, send an error message
|
||||
channelService.sendEmbedTemplateInMessageChannelList("modmail_no_server_available", new Object(), initialMessage.getChannel());
|
||||
availableGuilds.add(serverChoice);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
Map<String, ServerChoice> choices = new HashMap<>();
|
||||
ServerChoices serverChoices = ServerChoices
|
||||
.builder()
|
||||
.commonGuilds(choices)
|
||||
.userId(initialMessage.getAuthor().getIdLong())
|
||||
.messageId(initialMessage.getIdLong())
|
||||
.build();
|
||||
availableGuilds.forEach(serverChoice -> choices.put(componentService.generateComponentId(), serverChoice));
|
||||
ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel
|
||||
.builder()
|
||||
.choices(serverChoices)
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_modal_server_choice", modMailServerChooserModel);
|
||||
FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, initialMessage.getChannel()))
|
||||
.thenAccept(unused -> self.persistInitialCallbacks(serverChoices))
|
||||
.exceptionally(throwable -> {
|
||||
log.error("Failed to setup prompt message correctly", throwable);
|
||||
undoActionService.performActions(undoActions);
|
||||
return null;
|
||||
});
|
||||
log.debug("Displaying server choice message for user {} in channel {}.", user.getId(), initialMessage.getChannel().getId());
|
||||
} else if(availableGuilds.size() == 1) {
|
||||
// if exactly one server is available, open the thread directly
|
||||
ServerChoice onlyChoice = availableGuilds.get(0);
|
||||
Long chosenServerId = onlyChoice.getServerId();
|
||||
Guild guild = guildService.getGuildById(chosenServerId);
|
||||
boolean appeal = onlyChoice.getAppealModmail();
|
||||
log.info("Only one server available to modmail. Directly opening modmail thread for user {} in server {}.", initialMessage.getAuthor().getId(), chosenServerId);
|
||||
createModMailThreadForUser(initialMessage.getAuthor(), guild , initialMessage, true, undoActions, appeal)
|
||||
.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.warn("User {} which was not known in any of the servers tried to contact the bot.", user.getId());
|
||||
log.info("No server available to open a modmail thread in.");
|
||||
// in case there is no server available, send an error message
|
||||
channelService.sendEmbedTemplateInMessageChannel("modmail_no_server_available", new Object(), initialMessage.getChannel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,21 +489,20 @@ 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);
|
||||
List<CompletableFuture<Message>> messages = channelService.sendEmbedTemplateInMessageChannel("modmail_thread_header", header, channel);
|
||||
return CompletableFuture.allOf(messages.toArray(new CompletableFuture[0]));
|
||||
}
|
||||
|
||||
@@ -476,24 +513,16 @@ 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
|
||||
// close the existing one, so the user can start a new one
|
||||
self.closeModMailThreadInDb(modmailThreadId);
|
||||
String textToSend = templateService.renderTemplate("modmail_failed_to_forward_message", new Object());
|
||||
String textToSend = templateService.renderTemplate("modmail_failed_to_forward_message", new Object(), serverId);
|
||||
return channelService.sendTextToChannel(textToSend, messageFromUser.getChannel());
|
||||
}
|
||||
}
|
||||
@@ -505,11 +534,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 +578,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 +632,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 +661,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 +670,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 +702,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 +759,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 +779,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()) {
|
||||
@@ -769,9 +792,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
log.info("Notifying user about the closed modmail thread {}.", modMailThreadId);
|
||||
ModMailThread modMailThread = modMailThreadOpt.get();
|
||||
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 ->
|
||||
Long serverId = modMailThread.getServer().getId();
|
||||
String defaultValue = templateService.renderSimpleTemplate("modmail_closing_user_message_description", serverId);
|
||||
closingMessage.put("closingMessage", configService.getStringValue(MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY, serverId, defaultValue));
|
||||
return messageService.sendEmbedToUser(modMailThreaduser, "modmail_closing_user_message", closingMessage).thenCompose(message ->
|
||||
self.deleteChannelAndClose(modMailThreadId, undoActions)
|
||||
).exceptionally(throwable -> {
|
||||
self.deleteChannelAndClose(modMailThreadId, undoActions);
|
||||
@@ -852,7 +876,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
.loggedMessages(0)
|
||||
.totalMessages(messages.getMessages().size())
|
||||
.build();
|
||||
List<CompletableFuture<Message>> updateMessageFutures = channelService.sendEmbedTemplateInTextChannelList(MODMAIL_CLOSE_PROGRESS_TEMPLATE_KEY, progressModel, channel);
|
||||
List<CompletableFuture<Message>> updateMessageFutures = channelService.sendEmbedTemplateInMessageChannel(MODMAIL_CLOSE_PROGRESS_TEMPLATE_KEY, progressModel, channel);
|
||||
return FutureUtils.toSingleFutureGeneric(updateMessageFutures)
|
||||
.thenCompose(updateMessage -> self.logMessages(modMailThreadId, messages, context, updateMessageFutures.get(0).join()));
|
||||
}
|
||||
@@ -1002,6 +1026,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");
|
||||
|
||||
@@ -98,10 +98,11 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme
|
||||
* The status of the created instance is INITIAL.
|
||||
* @param userInAServer The {@link AUserInAServer} for which the thread was created for
|
||||
* @param channel An instance of {@link AChannel} in which the conversation with the member is handled
|
||||
* @param appeal Whether the modmail thread is for the purpose of an appeal
|
||||
* @return the created {@link ModMailThread} instance
|
||||
*/
|
||||
@Override
|
||||
public ModMailThread createModMailThread(AUserInAServer userInAServer, AChannel channel) {
|
||||
public ModMailThread createModMailThread(AUserInAServer userInAServer, AChannel channel, boolean appeal) {
|
||||
ModMailThread thread = ModMailThread
|
||||
.builder()
|
||||
.id(channel.getId())
|
||||
@@ -111,6 +112,7 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme
|
||||
.server(userInAServer.getServerReference())
|
||||
.state(ModMailThreadState.INITIAL)
|
||||
.updated(Instant.now())
|
||||
.appeal(appeal)
|
||||
.build();
|
||||
|
||||
log.info("Create modmail thread in channel {} for user {} in server {}.",
|
||||
|
||||
@@ -88,7 +88,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
|
||||
model.setServerId(user.getGuildId());
|
||||
}
|
||||
log.info("Executing mod mail category setup for server {}.", user.getGuildId());
|
||||
String messageText = templateService.renderTemplate(messageTemplateKey, model);
|
||||
String messageText = templateService.renderTemplate(messageTemplateKey, model, user.getGuildId());
|
||||
AChannel channel = channelManagementService.loadChannel(user.getChannelId());
|
||||
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(user.getGuildId(), user.getUserId());
|
||||
|
||||
@@ -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>
|
||||
@@ -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,12 @@
|
||||
<?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="mod_mail_thread-add_appeal_boolean">
|
||||
<addColumn tableName="mod_mail_thread">
|
||||
<column name="appeal" type="BOOLEAN" defaultValue="false">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user