Compare commits

...

12 Commits

Author SHA1 Message Date
Sheldan
062581fce5 [maven-release-plugin] prepare release v1.5.19 2023-12-26 21:04:45 +01:00
Sheldan
be41551529 [AB-xxx] preparing for release 2023-12-26 21:03:11 +01:00
Sheldan
af8206c529 [AB-xxx] adding bonk image generation command
fixing offline streamer handling not being able to handle streamer without current sessions
2023-12-26 15:42:02 +01:00
Sheldan
8efedf6f6f [AB-xxx] renaming pat sprite png 2023-12-25 23:44:43 +01:00
Sheldan
80aff40054 [AB-xxx] adding pat gif generator command 2023-12-25 23:43:34 +01:00
Sheldan
c71f5f004d [AB-xxx] changing displayed user for already existing user in modmail to be the target user 2023-12-25 12:58:47 +01:00
Sheldan
350a634f50 [maven-release-plugin] prepare for next development iteration 2023-12-25 01:07:26 +01:00
Sheldan
f5de74c1e4 [maven-release-plugin] prepare release v1.5.18 2023-12-25 01:07:21 +01:00
Sheldan
6e3809bfd9 [AB-xxx] prepare for release 2023-12-25 01:06:02 +01:00
Sheldan
8e6339a99b [AB-109] fixing streamers not being marked online if the post target is disabled 2023-12-25 01:00:54 +01:00
Sheldan
befef1f61d [AB-xxx] refactoring modmail to offer a feature mode to use threads instead of channels
adding various utilities for thread channels in core
fixing enable feature not showing validation messages
restructuring feature mode collection to be a startup listener, because postconstruct might not have the appropriate values available, and therefore not initialize the map correctly
2023-12-24 23:25:03 +01:00
Sheldan
1f0bc493d9 [maven-release-plugin] prepare for next development iteration 2023-12-23 23:18:06 +01:00
114 changed files with 950 additions and 203 deletions

2
.env
View File

@@ -1,2 +1,2 @@
REGISTRY_PREFIX=harbor.sheldan.dev/abstracto/
VERSION=1.5.17
VERSION=1.5.19

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>assignable-roles</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>assignable-roles-int</artifactId>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>custom-command</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>custom-command</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>dynamic-activity</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>dynamic-activity</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>entertainment</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>experience-tracking</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<artifactId>giveaway-impl</artifactId>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>giveaway</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<artifactId>giveaway-int</artifactId>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<artifactId>giveaway</artifactId>

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>image-generation</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<artifactId>image-generation-impl</artifactId>

View File

@@ -0,0 +1,147 @@
package dev.sheldan.abstracto.imagegeneration.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
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.core.service.ChannelService;
import dev.sheldan.abstracto.core.templating.model.AttachedFile;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.FileService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationFeatureDefinition;
import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationSlashCommandNames;
import dev.sheldan.abstracto.imagegeneration.service.ImageGenerationService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class Bonk extends AbstractConditionableCommand {
public static final String MEMBER_PARAMETER_KEY = "member";
@Autowired
private ImageGenerationService imageGenerationService;
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Autowired
private FileService fileService;
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
private static final String BONK_EMBED_TEMPLATE_KEY = "bonk_response";
@Value("${abstracto.feature.imagegeneration.bonk.imagesize}")
private Integer imageSize;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
Member member;
List<Object> parameters = commandContext.getParameters().getParameters();
if(parameters.isEmpty()) {
member = commandContext.getAuthor();
} else {
member = (Member) parameters.get(0);
}
File bonkGifFile = imageGenerationService.getBonkGif(member.getEffectiveAvatar().getUrl(imageSize));
MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object());
// template support does not support binary files
AttachedFile file = AttachedFile
.builder()
.file(bonkGifFile)
.fileName("bonk.gif")
.build();
messageToSend.getAttachedFiles().add(file);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenAccept(unused -> fileService.safeDeleteIgnoreException(messageToSend.getAttachedFiles().get(0).getFile()))
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
event.deferReply().queue();
Member targetMember;
if(slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER_KEY, event)) {
targetMember = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER_KEY, event, Member.class);
} else {
targetMember = event.getMember();
}
File bonkGifFile = imageGenerationService.getBonkGif(targetMember.getEffectiveAvatar().getUrl(imageSize));
MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object());
// template support does not support binary files
AttachedFile file = AttachedFile
.builder()
.file(bonkGifFile)
.fileName("bonk.gif")
.build();
messageToSend.getAttachedFiles().add(file);
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(messageToSend, event.getHook()))
.thenAccept(unused -> fileService.safeDeleteIgnoreException(messageToSend.getAttachedFiles().get(0).getFile()))
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
Parameter memberParameter = Parameter
.builder()
.name(MEMBER_PARAMETER_KEY)
.type(Member.class)
.templated(true)
.optional(true)
.build();
parameters.add(memberParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ImageGenerationSlashCommandNames.IMAGE_GENERATION)
.groupName("memes")
.commandName("bonk")
.build();
return CommandConfiguration.builder()
.name("bonk")
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.supportsEmbedException(true)
.async(true)
.slashCommandConfig(slashCommandConfig)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return ImageGenerationFeatureDefinition.IMAGE_GENERATION;
}
}

View File

@@ -0,0 +1,147 @@
package dev.sheldan.abstracto.imagegeneration.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
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.core.service.ChannelService;
import dev.sheldan.abstracto.core.templating.model.AttachedFile;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.FileService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationFeatureDefinition;
import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationSlashCommandNames;
import dev.sheldan.abstracto.imagegeneration.service.ImageGenerationService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class Pat extends AbstractConditionableCommand {
public static final String MEMBER_PARAMETER_KEY = "member";
@Autowired
private ImageGenerationService imageGenerationService;
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Autowired
private FileService fileService;
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
private static final String PAT_EMBED_TEMPLATE_KEY = "pat_response";
@Value("${abstracto.feature.imagegeneration.pat.imagesize}")
private Integer imageSize;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
Member member;
List<Object> parameters = commandContext.getParameters().getParameters();
if(parameters.isEmpty()) {
member = commandContext.getAuthor();
} else {
member = (Member) parameters.get(0);
}
File patGifFile = imageGenerationService.getPatGif(member.getEffectiveAvatar().getUrl(imageSize));
MessageToSend messageToSend = templateService.renderEmbedTemplate(PAT_EMBED_TEMPLATE_KEY, new Object());
// template support does not support binary files
AttachedFile file = AttachedFile
.builder()
.file(patGifFile)
.fileName("pat.gif")
.build();
messageToSend.getAttachedFiles().add(file);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenAccept(unused -> fileService.safeDeleteIgnoreException(messageToSend.getAttachedFiles().get(0).getFile()))
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
event.deferReply().queue();
Member targetMember;
if(slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER_KEY, event)) {
targetMember = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER_KEY, event, Member.class);
} else {
targetMember = event.getMember();
}
File patGifFile = imageGenerationService.getPatGif(targetMember.getEffectiveAvatar().getUrl(imageSize));
MessageToSend messageToSend = templateService.renderEmbedTemplate(PAT_EMBED_TEMPLATE_KEY, new Object());
// template support does not support binary files
AttachedFile file = AttachedFile
.builder()
.file(patGifFile)
.fileName("pat.gif")
.build();
messageToSend.getAttachedFiles().add(file);
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(messageToSend, event.getHook()))
.thenAccept(unused -> fileService.safeDeleteIgnoreException(messageToSend.getAttachedFiles().get(0).getFile()))
.thenApply(unused -> CommandResult.fromIgnored());
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
Parameter memberParameter = Parameter
.builder()
.name(MEMBER_PARAMETER_KEY)
.type(Member.class)
.templated(true)
.optional(true)
.build();
parameters.add(memberParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ImageGenerationSlashCommandNames.IMAGE_GENERATION)
.groupName("memes")
.commandName("pat")
.build();
return CommandConfiguration.builder()
.name("pat")
.module(UtilityModuleDefinition.UTILITY)
.templated(true)
.supportsEmbedException(true)
.async(true)
.slashCommandConfig(slashCommandConfig)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return ImageGenerationFeatureDefinition.IMAGE_GENERATION;
}
}

View File

@@ -73,7 +73,7 @@ public class Triggered extends AbstractConditionableCommand {
AttachedFile file = AttachedFile
.builder()
.file(triggeredGifFile)
.fileName("avatar.gif")
.fileName("triggered.gif")
.build();
messageToSend.getAttachedFiles().add(file);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
@@ -96,7 +96,7 @@ public class Triggered extends AbstractConditionableCommand {
AttachedFile file = AttachedFile
.builder()
.file(triggeredGifFile)
.fileName("avatar.gif")
.fileName("triggered.gif")
.build();
messageToSend.getAttachedFiles().add(file);
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(messageToSend, event.getHook()))

View File

@@ -16,6 +16,11 @@ public class ImageGenerationServiceBean implements ImageGenerationService {
@Value("${abstracto.feature.imagegeneration.triggered.url}")
private String triggeredUrl;
@Value("${abstracto.feature.imagegeneration.pat.url}")
private String patUrl;
@Value("${abstracto.feature.imagegeneration.bonk.url}")
private String bonkUrl;
@Autowired
private HttpService httpService;
@@ -29,4 +34,22 @@ public class ImageGenerationServiceBean implements ImageGenerationService {
}
}
@Override
public File getPatGif(String imageUrl) {
try {
return httpService.downloadFileToTempFile(patUrl.replace("{1}", imageUrl));
} catch (IOException e) {
throw new AbstractoRunTimeException(String.format("Failed to download pat gif for url %s with error %s", imageUrl, e.getMessage()));
}
}
@Override
public File getBonkGif(String imageUrl) {
try {
return httpService.downloadFileToTempFile(bonkUrl.replace("{1}", imageUrl));
} catch (IOException e) {
throw new AbstractoRunTimeException(String.format("Failed to download bonk gif for url %s with error %s", imageUrl, e.getMessage()));
}
}
}

View File

@@ -2,4 +2,10 @@ abstracto.featureFlags.imageGeneration.featureName=imageGeneration
abstracto.featureFlags.imageGeneration.enabled=false
abstracto.feature.imagegeneration.triggered.url=http://${PRIVATE_REST_API_HOST}:${PRIVATE_REST_API_PORT}/memes/triggered/file.gif?url={1}
abstracto.feature.imagegeneration.triggered.imagesize=128
abstracto.feature.imagegeneration.triggered.imagesize=128
abstracto.feature.imagegeneration.pat.url=http://${PRIVATE_REST_API_HOST}:${PRIVATE_REST_API_PORT}/memes/pat/file.gif?url={1}
abstracto.feature.imagegeneration.pat.imagesize=128
abstracto.feature.imagegeneration.bonk.url=http://${PRIVATE_REST_API_HOST}:${PRIVATE_REST_API_PORT}/memes/bonk/file.gif?url={1}
abstracto.feature.imagegeneration.bonk.imagesize=128

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,25 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
<property name="imageGenerationFeature" value="(SELECT id FROM feature WHERE key = 'imageGeneration')"/>
<changeSet author="Sheldan" id="pat_bonk-commands">
<insert tableName="command">
<column name="name" value="pat"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${imageGenerationFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="bonk"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${imageGenerationFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="command.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -7,4 +7,5 @@
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="1.5.15/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.19/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -4,7 +4,7 @@
<parent>
<artifactId>image-generation</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<artifactId>image-generation-int</artifactId>

View File

@@ -4,4 +4,6 @@ import java.io.File;
public interface ImageGenerationService {
File getTriggeredGif(String imageUrl);
File getPatGif(String imageUrl);
File getBonkGif(String imageUrl);
}

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<artifactId>image-generation</artifactId>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>invite-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>invite-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>link-embed</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>link-embed</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>logging</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>logging</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>modmail</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -82,7 +82,7 @@ public class Contact extends AbstractConditionableCommand {
ModMailThreadExistsModel model = ModMailThreadExistsModel
.builder()
.existingModMailThread(existingThread)
.executingMemberDisplay(MemberNameDisplay.fromMember(commandContext.getAuthor()))
.executingMemberDisplay(MemberNameDisplay.fromMember(targetUser))
.build();
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInTextChannelList(MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE, model, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());

View File

@@ -40,6 +40,7 @@ import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
@@ -56,14 +57,12 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;
import static dev.sheldan.abstracto.modmail.config.ModMailFeatureConfig.MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY;
@Component
@Slf4j
public class ModMailThreadServiceBean implements ModMailThreadService {
/**
* The config key to use for the closing text
*/
public static final String MODMAIL_CLOSING_MESSAGE_TEXT = "modMailClosingText";
/**
* The config key to use for the ID of the category to create {@link GuildMessageChannel} in
*/
@@ -190,11 +189,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override
public CompletableFuture<MessageChannel> createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions) {
Long serverId = member.getGuild().getIdLong();
Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId);
User user = member.getUser();
AServer server = serverManagementService.loadServer(member.getGuild().getIdLong());
metricService.incrementCounter(MODMAIL_THREAD_CREATED_COUNTER);
User user = member.getUser();
log.info("Creating modmail channel for user {} in category {} on server {}.", user.getId(), categoryId, serverId);
ModMailChannelNameModel model = ModMailChannelNameModel
.builder()
.serverId(serverId)
@@ -204,12 +201,36 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.currentDate(Instant.now())
.build();
String channelName = templateService.renderTemplate(TEXT_CHANNEL_NAME_TEMPLATE_KEY, model, serverId);
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)
.thenCompose(unused -> CompletableFuture.completedFuture(channel));
});
if (featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, serverId, ModMailMode.THREAD_CONTAINER)) {
MessageToSend notificationMessageToSend = getModmailNotificationMessageToSend(member, null, serverId, false);
Optional<GuildMessageChannel> modmailContainerOptional = postTargetService.getPostTargetChannel(ModMailPostTargets.MOD_MAIL_CONTAINER, serverId);
if(modmailContainerOptional.isEmpty()) {
throw new AbstractoRunTimeException("Modmail thread container not setup.");
}
GuildMessageChannel modmailContainer = modmailContainerOptional.get();
Optional<TextChannel> textChannelOptional = channelService.getTextChannelFromServerOptional(serverId, modmailContainer.getIdLong());
if(textChannelOptional.isEmpty()) {
throw new AbstractoRunTimeException("Modmail thread container text channel not found.");
}
TextChannel textChannel = textChannelOptional.get();
List<CompletableFuture<Message>> notificationMessage = channelService.sendMessageToSendToChannel(notificationMessageToSend, modmailContainer);
return FutureUtils.toSingleFutureGeneric(notificationMessage)
.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)
.thenCompose(unused -> CompletableFuture.completedFuture(threadChannel));
});
} else {
Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId);
log.info("Creating modmail channel for user {} in category {} on server {}.", user.getId(), categoryId, serverId);
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)
.thenCompose(unused -> CompletableFuture.completedFuture(channel));
});
}
}
@Transactional
@@ -239,12 +260,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @param member The {@link Member} 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 or not the thread was initiated by a member
* @param userInitiated Whether the thread was initiated by a member
* @param undoActions The list of actions to undo, in case an exception occurs
* @return A {@link CompletableFuture future} which completes when the setup is done
*/
@Transactional
public CompletableFuture<Void> performModMailThreadSetup(Member member, Message initialMessage, TextChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions) {
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);
CompletableFuture<Message> userReplyMessage;
@@ -268,7 +289,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
@Transactional
public void setupModMailThreadInDB(Message initialMessage, TextChannel channel, Member member, Message sendMessage) {
public void setupModMailThreadInDB(Message initialMessage, GuildMessageChannel channel, Member member, Message sendMessage) {
log.info("Persisting info about modmail thread {} in database.", channel.getIdLong());
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
ModMailThread thread = createThreadObject(channel, aUserInAServer);
@@ -281,15 +302,25 @@ 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 channel The created {@link TextChannel} in which the mod mail thread is dealt with
* @return A {@link CompletableFuture future} which complets when the notification has been sent
* @param channel The created {@link GuildMessageChannel} in which the mod mail thread is dealt with
* @return A {@link CompletableFuture future} which completes when the notification has been sent
*/
@Transactional
public CompletableFuture<Void> sendModMailNotification(Member member, TextChannel channel) {
public CompletableFuture<Void> sendModMailNotification(Member member, GuildMessageChannel channel) {
Long serverId = member.getGuild().getIdLong();
MessageToSend messageToSend = getModmailNotificationMessageToSend(member, channel, serverId, true);
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_PING, serverId));
}
private MessageToSend getModmailNotificationMessageToSend(Member member, GuildMessageChannel channel, Long serverId, boolean pingRole) {
log.info("Sending modmail notification for new modmail thread about user {} in server {}.", member.getId(), serverId);
AServer server = serverManagementService.loadServer(serverId);
List<ModMailRole> rolesToPing = modMailRoleManagementService.getRolesForServer(server);
List<ModMailRole> rolesToPing;
if(pingRole) {
rolesToPing = modMailRoleManagementService.getRolesForServer(server);
} else {
rolesToPing = new ArrayList<>();
}
log.debug("Pinging {} roles to notify about modmail thread about user {} in server {}.", rolesToPing.size(), member.getId(), serverId);
ModMailNotificationModel modMailNotificationModel = ModMailNotificationModel
.builder()
@@ -297,29 +328,31 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.roles(rolesToPing)
.channel(channel)
.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_notification_message", modMailNotificationModel, channel.getGuild().getIdLong());
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_PING, serverId));
return templateService.renderEmbedTemplate("modmail_notification_message", modMailNotificationModel, serverId);
}
/**
* Creates the instance of the {@link ModMailThread} in the database.
* @param channel The {@link TextChannel} in which the {@link ModMailThread} is being done
* @param channel The {@link GuildMessageChannel} in which the {@link ModMailThread} is being done
* @param user The {@link AUserInAServer} which the thread is about
* @return The created instance of {@link ModMailThread}
*/
public ModMailThread createThreadObject(TextChannel channel, AUserInAServer user) {
public ModMailThread createThreadObject(GuildMessageChannel channel, AUserInAServer user) {
log.info("Creating database objects related to modmail thread in channel {} and about user {} in server {}.", channel.getIdLong(), user.getUserReference().getId(), channel.getGuild().getId());
AChannel channel2 = channelManagementService.createChannel(channel.getIdLong(), AChannelType.TEXT, user.getServerReference());
log.info("Creating mod mail thread in channel {} with db channel {}", channel.getIdLong(), channel2.getId());
return modMailThreadManagementService.createModMailThread(user, channel2);
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);
}
@Override
public void setModMailCategoryTo(Guild guild, Long categoryId) {
log.info("Trying to set modmail category to {} in guild {}.", categoryId, guild.getId());
FeatureValidationResult result = FeatureValidationResult.builder().build();
FeatureValidationResult result = FeatureValidationResult
.builder()
.build();
modMailFeatureValidator.validateModMailCategory(result, guild, categoryId);
if(result.getValidationResult()) {
if(!result.getValidationResult()) {
throw new ModMailCategoryIdException(categoryId);
}
configService.setLongValue(MODMAIL_CATEGORY, guild.getIdLong(), categoryId);
@@ -416,10 +449,10 @@ 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 TextChannel} in which the mod mail thread is present in
* @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
*/
private CompletableFuture<Void> sendModMailHeader(TextChannel channel, Member member) {
private CompletableFuture<Void> sendModMailHeader(GuildMessageChannel channel, Member member) {
log.debug("Sending modmail thread header for tread in channel {} on server {}.", channel.getIdLong(), channel.getGuild().getId());
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
ModMailThread latestThread = modMailThreadManagementService.getLatestModMailThread(aUserInAServer);
@@ -472,8 +505,8 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @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 or not the modmail thread already exists and is persisted.
* @return A {@link CompletableFuture} which resolves when the post processing of the message is completed (adding read notification, and storing messageIDs)
* @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) {
List<CompletableFuture<Member>> subscriberMemberFutures = new ArrayList<>();
@@ -548,7 +581,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}
/**
* This message handles the post processing of the messages received by the user. This includes: saving the messageIDs
* This message handles the postprocessing of the messages received by the user. This includes: saving the messageIDs
* in the database, updating the state of the {@link ModMailThread} and adding the read reaction to the user message
* @param textChannel The channel in which the message
* @param messageInModMailThread The actual {@link Message} instance which was sent to the mod mail thread
@@ -640,22 +673,31 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
List<ModMailMessage> modMailMessages = modMailThread.getMessages();
Long userId = modMailThread.getUser().getUserReference().getId();
Long serverId = modMailThread.getServer().getId();
if(closingConfig.getLog()) {
if(!modMailMessages.isEmpty()) {
return modMailMessageService.loadModMailMessages(modMailMessages)
.thenAccept(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)
));
}
if (featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, serverId, ModMailMode.THREAD_CONTAINER)) {
ThreadChannel threadChannel = channelService.getThreadChannel(modMailThread.getChannel().getId());
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));
} else {
log.debug("Not logging modmail thread {}.", modMailThreadId);
return memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), member, undoActions)
);
if(closingConfig.getLog()) {
if(!modMailMessages.isEmpty()) {
return modMailMessageService.loadModMailMessages(modMailMessages)
.thenAccept(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)
));
}
} else {
log.debug("Not logging modmail thread {}.", modMailThreadId);
return memberService.getMemberInServerAsync(modMailThread.getUser()).thenCompose(member ->
self.afterSuccessfulLog(modMailThreadId, closingConfig.getNotifyUser(), member, undoActions)
);
}
}
}
@@ -711,7 +753,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* This message is executed after the thread has been logged and notifies the user about the closed {@link ModMailThread}
* which a configurable closing text. This method then calls the method to delete the channel.
* @param modMailThreadId The ID of the {@link ModMailThread} which is being closed.
* @param notifyUser Whether or not the user should be notified
* @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
* @throws ModMailThreadNotFoundException in case the {@link ModMailThread} is not found by the ID
@@ -727,7 +769,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
ModMailThread modMailThread = modMailThreadOpt.get();
HashMap<String, String> closingMessage = new HashMap<>();
String defaultValue = templateService.renderSimpleTemplate("modmail_closing_user_message_description");
closingMessage.put("closingMessage", configService.getStringValue(MODMAIL_CLOSING_MESSAGE_TEXT, modMailThread.getServer().getId(), defaultValue));
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 ->
self.deleteChannelAndClose(modMailThreadId, undoActions)
).exceptionally(throwable -> {
@@ -758,11 +800,17 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
ModMailThread modMailThread = modMailThreadOpt.get();
String failureMessage = "Failed to delete text channel containing mod mail thread {}";
try {
log.debug("Deleting channel {} which contained the modmail thread {}.", modMailThread.getChannel().getId(), modMailThreadId);
return channelService.deleteTextChannel(modMailThread.getChannel()).thenAccept(avoid -> {
if (featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, modMailThread.getServer().getId(), ModMailMode.THREAD_CONTAINER)) {
undoActions.clear();
self.closeModMailThreadInDb(modMailThreadId);
});
return CompletableFuture.completedFuture(null);
} else {
log.debug("Deleting channel {} which contained the modmail thread {}.", modMailThread.getChannel().getId(), modMailThreadId);
return channelService.deleteTextChannel(modMailThread.getChannel()).thenAccept(avoid -> {
undoActions.clear();
self.closeModMailThreadInDb(modMailThreadId);
});
}
} catch (InsufficientPermissionException ex) {
log.error(failureMessage, modMailThreadId, ex);
String message = "Failed To delete mod mail thread channel because no permissions.";
@@ -864,16 +912,22 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.serverId(modMailThread.getServer().getId())
.userId(modMailThread.getUser().getUserReference().getId())
.build();
Long modmailThreadId = modMailThread.getId();
return userService.retrieveUserForId(modMailThread.getUser().getUserReference().getId()).thenApply(user -> {
headerModel.setUser(user);
return self.sendClosingHeader(headerModel).get(0);
return self.sendClosingHeader(headerModel, modmailThreadId).get(0);
}).thenCompose(Function.identity());
}
@Transactional
public List<CompletableFuture<Message>> sendClosingHeader(ModMailClosingHeaderModel model) {
public List<CompletableFuture<Message>> sendClosingHeader(ModMailClosingHeaderModel model, Long modmailThreadId) {
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_header", model, model.getServerId());
return postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_LOG, model.getServerId());
if (featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, model.getServerId(), ModMailMode.THREAD_CONTAINER)) {
ModMailThread modMailThread = modMailThreadManagementService.getById(modmailThreadId);
return channelService.sendMessageEmbedToSendToAChannel(messageToSend, modMailThread.getChannel());
} else {
return postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_LOG, model.getServerId());
}
}
/**
@@ -899,7 +953,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* sends this to the appropriate logging {@link PostTarget}
* @param modMailThreadId The ID of {@link ModMailThread} to which the loaded messages belong to
* @param loadedMessages The list of {@link ModMailLoggedMessageModel} which can be rendered
* @return A list of {@link CompletableFuture} which represent each of the messages being send to the {@link PostTarget}
* @return A list of {@link CompletableFuture} which represent each of the messages being sent to the {@link PostTarget}
*/
public List<CompletableFuture<Message>> sendMessagesToPostTarget(Long modMailThreadId, List<ModMailLoggedMessageModel> loadedMessages, Message updateMessage) {
List<CompletableFuture<Message>> messageFutures = new ArrayList<>();

View File

@@ -3,21 +3,25 @@ package dev.sheldan.abstracto.modmail.validator;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.models.FeatureValidationResult;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.service.FeatureValidatorService;
import dev.sheldan.abstracto.core.service.GuildService;
import dev.sheldan.abstracto.core.service.*;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailMode;
import dev.sheldan.abstracto.modmail.config.ModMailPostTargets;
import dev.sheldan.abstracto.modmail.model.template.ModMailCategoryValidationErrorModel;
import dev.sheldan.abstracto.modmail.model.template.ModMailThreadContainerValidationErrorModel;
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer;
import net.dv8tion.jda.api.entities.channel.concrete.Category;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* This component is used to validate whether or not the mod mail feature has a mod mail category configured, which points to
* This component is used to validate whether the mod mail feature has a mod mail category configured, which points to
* a category on the server it is configured for. This and other {@link dev.sheldan.abstracto.core.service.FeatureValidator}
* are used to fully validate the mod mail feature.
*/
@@ -34,8 +38,16 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
@Autowired
private FeatureValidatorService featureValidatorService;
@Autowired
private FeatureModeService featureModeService;
@Autowired
private PostTargetService postTargetService;
/**
* Checks if the mod mail category contains a value and whether or not this valid also points to a {@link Category}
* Checks if the mod mail category contains a value and whether this valid also points to a {@link Category}.
* Additionally, if the thread container feature mode is already enabled. This will check if the current posttarget
* for threads can hold threads.
* @param featureConfig The instance of {@link FeatureConfig} of mod mail
* @param server The {@link AServer} to check the config for
* @param validationResult The current {@link FeatureValidationResult} used to accumulate the wrong values
@@ -52,6 +64,29 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
Long modMailCategory = configService.getLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, server.getId());
validateModMailCategory(validationResult, guild, modMailCategory);
}
if (featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, server.getId(), ModMailMode.THREAD_CONTAINER)) {
Optional<GuildMessageChannel> modmailContainerOptional = postTargetService.getPostTargetChannel(ModMailPostTargets.MOD_MAIL_CONTAINER, server.getId());
if(modmailContainerOptional.isEmpty()) {
ModMailThreadContainerValidationErrorModel newError = ModMailThreadContainerValidationErrorModel
.builder()
.currentChannelId(null)
.build();
validationResult.getValidationErrorModels().add(newError);
validationResult.setValidationResult(false);
} else {
GuildMessageChannel threadContainer = modmailContainerOptional.get();
if(!(threadContainer instanceof IThreadContainer)) {
validationResult.setValidationResult(false);
ModMailThreadContainerValidationErrorModel newError = ModMailThreadContainerValidationErrorModel
.builder()
.currentChannelId(threadContainer.getIdLong())
.build();
validationResult.getValidationErrorModels().add(newError);
} else {
validationResult.setValidationResult(true);
}
}
}
}
}
@@ -70,6 +105,8 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
.currentCategoryId(modMailCategory)
.build();
validationResult.getValidationErrorModels().add(newError);
} else {
validationResult.setValidationResult(true);
}
}
}

View File

@@ -9,11 +9,16 @@ abstracto.featureFlags.modmail.enabled=false
abstracto.postTargets.modmailLog.name=modmailLog
abstracto.postTargets.modmailPing.name=modmailPing
abstracto.postTargets.modmailContainer.name=modmailContainer
abstracto.featureModes.log.featureName=modmail
abstracto.featureModes.log.mode=log
abstracto.featureModes.log.enabled=true
abstracto.featureModes.threadContainer.featureName=modmail
abstracto.featureModes.threadContainer.mode=threadContainer
abstracto.featureModes.threadContainer.enabled=false
abstracto.featureModes.threadMessage.featureName=modmail
abstracto.featureModes.threadMessage.mode=threadMessage
abstracto.featureModes.threadMessage.enabled=true

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>modmail</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -20,6 +20,7 @@ import java.util.List;
@Component
public class ModMailFeatureConfig implements FeatureConfig {
public static final String MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY = "modMailClosingText";
@Autowired
private ModMailFeatureValidator modMailFeatureValidator;
@@ -33,7 +34,7 @@ public class ModMailFeatureConfig implements FeatureConfig {
@Override
public List<PostTargetEnum> getRequiredPostTargets() {
return Arrays.asList(ModMailPostTargets.MOD_MAIL_PING, ModMailPostTargets.MOD_MAIL_LOG);
return Arrays.asList(ModMailPostTargets.MOD_MAIL_PING, ModMailPostTargets.MOD_MAIL_LOG, ModMailPostTargets.MOD_MAIL_CONTAINER);
}
@Override
@@ -48,12 +49,12 @@ public class ModMailFeatureConfig implements FeatureConfig {
@Override
public List<FeatureMode> getAvailableModes() {
return Arrays.asList(ModMailMode.LOGGING, ModMailMode.SEPARATE_MESSAGE);
return Arrays.asList(ModMailMode.LOGGING, ModMailMode.SEPARATE_MESSAGE, ModMailMode.THREAD_CONTAINER);
}
@Override
public List<String> getRequiredSystemConfigKeys() {
return Arrays.asList("modMailClosingText");
return Arrays.asList(MOD_MAIL_CLOSING_TEXT_SYSTEM_CONFIG_KEY);
}
@Override

View File

@@ -9,7 +9,7 @@ import lombok.Getter;
*/
@Getter
public enum ModMailMode implements FeatureMode {
LOGGING("log"), SEPARATE_MESSAGE("threadMessage");
LOGGING("log"), SEPARATE_MESSAGE("threadMessage"), THREAD_CONTAINER("threadContainer");
private final String key;

View File

@@ -12,7 +12,11 @@ public enum ModMailPostTargets implements PostTargetEnum {
/**
* The channel to be used to log the contents of closed mod mail threads
*/
MOD_MAIL_LOG("modmailLog");
MOD_MAIL_LOG("modmailLog"),
/**
* The thread used as a container for the modmail threads
*/
MOD_MAIL_CONTAINER("modmailContainer");
private String key;

View File

@@ -41,4 +41,5 @@ public class ModMailClosingHeaderModel {
private Boolean silently;
private User user;
private Long serverId;
private Long modmailThreadId;
}

View File

@@ -8,7 +8,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import java.util.List;
@@ -33,7 +33,7 @@ public class ModMailNotificationModel extends ServerContext {
*/
private List<ModMailRole> roles;
/**
* The {@link TextChannel} in which the mod mail thread is handled
* The {@link GuildMessageChannel} in which the mod mail thread is handled
*/
private TextChannel channel;
private GuildMessageChannel channel;
}

View File

@@ -0,0 +1,23 @@
package dev.sheldan.abstracto.modmail.model.template;
import dev.sheldan.abstracto.core.models.ValidationErrorModel;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class ModMailThreadContainerValidationErrorModel implements ValidationErrorModel {
private Long currentChannelId;
@Override
public String getTemplateName() {
return "feature_setup_modmail_thread_container_not_setup";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto</groupId>
<artifactId>abstracto-application</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>profanity-filter</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>profanity-filter</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>remind</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>remind</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>repost-detection</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>repost-detection</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>starboard</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>starboard</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>statistic</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>suggestion</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>suggestion</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>twitch</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -314,7 +314,8 @@ public class StreamerServiceBean implements StreamerService {
}
log.info("Streamer {} went offline.", streamerId);
if (deleteFlagValues.computeIfAbsent(streamer.getServer().getId(),
aLong -> featureModeService.featureModeActive(TwitchFeatureDefinition.TWITCH, aLong, TwitchFeatureMode.DELETE_NOTIFICATION))) {
aLong -> featureModeService.featureModeActive(TwitchFeatureDefinition.TWITCH, aLong, TwitchFeatureMode.DELETE_NOTIFICATION))
&& streamer.getCurrentSession() != null) {
Long channelId = streamer.getCurrentSession().getChannel().getId();
Long messageId = streamer.getCurrentSession().getId();
messageService.deleteMessageInChannelInServer(streamer.getServer().getId(), channelId, messageId).thenAccept(unused -> {
@@ -400,23 +401,37 @@ public class StreamerServiceBean implements StreamerService {
}
streamer.setCurrentGameId(stream.getGameId());
}
return;
}
CompletableFutureList<Message> messages = notifyAboutOnlineStream(stream, streamer, streamerUser);
messages.getMainFuture()
.thenAccept(unused -> {
Message message = messages.getFutures().get(0).join();
if(message != null) {
} else if(currentSession == null &&
!postTargetService.postTargetUsableInServer(TwitchPostTarget.TWITCH_LIVE_NOTIFICATION, server.getId())) {
// this is the case in which the streamer is online, and we should in theory notify about the online status
// _but_ the difference is that there is no current session on going - as the sessions in our database are
// bound to actual notifications sent, and this is the case in which the post target has been disabled.
// In this case we only update current game if necessary
// this only really serves as a shortcut to not evaluate and create a full MessageToSend object
// just to not actually send it
if(streamer.getCurrentGameId() == null || !streamer.getCurrentGameId().equals(stream.getGameId())) {
log.info("Game for streamer {} has changed - updating game.", streamerId);
streamer.setCurrentGameId(stream.getGameId());
}
streamer.setOnline(true);
streamerManagementService.saveStreamer(streamer);
} else {
CompletableFutureList<Message> messages = notifyAboutOnlineStream(stream, streamer, streamerUser);
messages.getMainFuture()
.thenAccept(unused -> {
Message message = messages.getFutures().get(0).join();
try {
self.storeStreamNotificationMessage(message, streamerId, stream);
if(message != null) {
self.storeStreamNotificationMessage(message, streamerId, stream);
}
} catch (Exception exception) {
log.error("Failed to store stream notification message of streamer {}.", streamerId, exception);
log.error("Failed to update streamer {} in database.", streamerId, exception);
}
}
}).exceptionally(throwable -> {
log.error("Failed to notify about online stream of streamer {}.", streamerId, throwable);
return null;
});
}).exceptionally(throwable -> {
log.error("Failed to notify about online stream of streamer {}.", streamerId, throwable);
return null;
});
}
}
@Transactional

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>twitch</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>utility</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>utility</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>voice-channel-context</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>voice-channel-context</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>abstracto-modules</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>webservices</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>webservices</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto</groupId>
<artifactId>abstracto-application</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.core</groupId>
<artifactId>core</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>

View File

@@ -73,7 +73,17 @@ public class EnableFeature extends AbstractConditionableCommand {
EnableFeatureResult result = enableFeature(serverId, featureKey);
if(result.featureDependencies.isEmpty()) {
return CompletableFuture.completedFuture(CommandResult.fromSuccess());
if(!result.validationResult.getValidationResult()) {
FeatureSwitchModel model = FeatureSwitchModel
.builder()
.validationText(result.validationResult.getValidationText())
.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate(ENABLE_FEATURE_RESPONSE_TEMPLATE_KEY, model, serverId);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(message -> CommandResult.fromIgnored());
} else {
return CompletableFuture.completedFuture(CommandResult.fromSuccess());
}
} else {
List<String> additionalFeatures = result.featureDependencies
.stream()
@@ -96,7 +106,11 @@ public class EnableFeature extends AbstractConditionableCommand {
String featureName = slashCommandParameterService.getCommandOption(FEATURE_NAME_PARAMETER, event, String.class);
EnableFeatureResult enableFeatureResult = enableFeature(event.getGuild().getIdLong(), featureName);
if(enableFeatureResult.featureDependencies.isEmpty()) {
return interactionService.replyEmbed(ENABLE_FEATURE_RESPONSE_TEMPLATE_KEY, event)
FeatureSwitchModel model = FeatureSwitchModel
.builder()
.validationText(enableFeatureResult.validationResult.getValidationText())
.build();
return interactionService.replyEmbed(ENABLE_FEATURE_RESPONSE_TEMPLATE_KEY, model, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
} else {
List<String> additionalFeatures = enableFeatureResult.featureDependencies

View File

@@ -19,6 +19,7 @@ import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.channel.concrete.Category;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
@@ -196,11 +197,8 @@ public class ChannelServiceBean implements ChannelService {
@Override
public List<CompletableFuture<Message>> sendMessageToSendToChannel(MessageToSend messageToSend, MessageChannel textChannel) {
if(messageToSend.getEphemeral()) {
throw new IllegalArgumentException("Ephemeral messages are only supported in interaction context.");
}
if(textChannel instanceof GuildMessageChannel) {
GuildMessageChannel guildMessageChannel = (GuildMessageChannel) textChannel;
messageToSend.setEphemeral(false);
if(textChannel instanceof GuildMessageChannel guildMessageChannel) {
long maxFileSize = guildMessageChannel.getGuild().getMaxFileSize();
// in this case, we cannot upload the file, so we need to fail
messageToSend.getAttachedFiles().forEach(attachedFile -> {
@@ -427,6 +425,16 @@ public class ChannelServiceBean implements ChannelService {
return channel.editMessageComponentsById(messageId, new ArrayList<>()).submit();
}
@Override
public ThreadChannel getThreadChannel(Long threadChannelId) {
return botService.getInstance().getThreadChannelById(threadChannelId);
}
@Override
public CompletableFuture<Void> archiveThreadChannel(ThreadChannel threadChannel) {
return threadChannel.getManager().setArchived(true).submit();
}
@Override
public CompletableFuture<Void> deleteTextChannel(AChannel channel) {
return deleteTextChannel(channel.getServer().getId(), channel.getId());
@@ -434,11 +442,11 @@ public class ChannelServiceBean implements ChannelService {
@Override
public CompletableFuture<Void> deleteTextChannel(Long serverId, Long channelId) {
TextChannel textChannelById = botService.getInstance().getTextChannelById(channelId);
if(textChannelById != null) {
GuildChannel channelById = botService.getInstance().getGuildChannelById(channelId);
if(channelById != null) {
log.info("Deleting channel {} on server {}.", channelId, serverId);
metricService.incrementCounter(CHANNEL_DELETE_METRIC);
return textChannelById.delete().submit();
return channelById.delete().submit();
}
throw new ChannelNotInGuildException(channelId);
}
@@ -508,6 +516,21 @@ public class ChannelServiceBean implements ChannelService {
throw new GuildNotFoundException(server.getId());
}
@Override
public CompletableFuture<ThreadChannel> createThread(TextChannel textChannel, String name) {
return textChannel.createThreadChannel(name).submit();
}
@Override
public CompletableFuture<ThreadChannel> createThreadWithStarterMessage(TextChannel textChannel, String name, Long messageId) {
return textChannel.createThreadChannel(name, messageId).submit();
}
@Override
public CompletableFuture<ThreadChannel> createPrivateThread(TextChannel textChannel, String name) {
return textChannel.createThreadChannel(name, true).submit();
}
@Override
public Optional<GuildChannel> getChannelFromAChannel(AChannel channel) {
return getGuildChannelFromServerOptional(channel.getServer().getId(), channel.getId());

View File

@@ -53,9 +53,12 @@ public class FeatureConfigServiceBean implements FeatureConfigService {
@Override
public FeatureConfig getFeatureDisplayForFeature(FeatureDefinition featureDefinition) {
Optional<FeatureConfig> any = getAllFeatureConfigs().stream().filter(featureDisplay -> featureDisplay.getFeature().equals(featureDefinition)).findAny();
if(any.isPresent()) {
return any.get();
List<FeatureConfig> allFeatureConfigs = getAllFeatureConfigs();
if(allFeatureConfigs != null) {
Optional<FeatureConfig> any = allFeatureConfigs.stream().filter(featureDisplay -> featureDisplay.getFeature().equals(featureDefinition)).findAny();
if(any.isPresent()) {
return any.get();
}
}
throw new FeatureNotFoundException(featureDefinition.getKey(), getFeaturesAsList());
}

View File

@@ -7,6 +7,7 @@ import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.config.FeatureMode;
import dev.sheldan.abstracto.core.exception.FeatureModeNotFoundException;
import dev.sheldan.abstracto.core.listener.AsyncStartupListener;
import dev.sheldan.abstracto.core.models.database.*;
import dev.sheldan.abstracto.core.models.property.FeatureModeProperty;
import dev.sheldan.abstracto.core.models.template.commands.AFeatureModeDisplay;
@@ -15,17 +16,18 @@ import dev.sheldan.abstracto.core.service.management.DefaultFeatureModeManagemen
import dev.sheldan.abstracto.core.service.management.FeatureFlagManagementService;
import dev.sheldan.abstracto.core.service.management.FeatureModeManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
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 javax.annotation.PostConstruct;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@Component
public class FeatureModeServiceBean implements FeatureModeService {
@Slf4j
public class FeatureModeServiceBean implements FeatureModeService, AsyncStartupListener {
@Autowired
private FeatureConfigService featureConfigService;
@@ -122,7 +124,10 @@ public class FeatureModeServiceBean implements FeatureModeService {
@Override
public List<FeatureMode> getAllAvailableFeatureModes() {
List<FeatureMode> fullFeatureModes = new ArrayList<>();
featureConfigService.getAllFeatureConfigs().forEach(featureConfig -> fullFeatureModes.addAll(featureConfig.getAvailableModes()));
List<FeatureConfig> allFeatureConfigs = featureConfigService.getAllFeatureConfigs();
if(allFeatureConfigs != null) {
allFeatureConfigs.forEach(featureConfig -> fullFeatureModes.addAll(featureConfig.getAvailableModes()));
}
return fullFeatureModes;
}
@@ -209,13 +214,16 @@ public class FeatureModeServiceBean implements FeatureModeService {
}
@PostConstruct
public void postConstruct() {
featureConfigService.getAllFeatureConfigs().forEach(featureConfig -> {
List<String> modes = new ArrayList<>();
featureConfig.getAvailableModes().forEach(featureMode -> modes.add(featureMode.getKey()));
featureModes.put(featureConfig.getFeature().getKey(), modes);
});
@Override
public void execute() {
List<FeatureConfig> allFeatureConfigs = featureConfigService.getAllFeatureConfigs();
log.info("Loading feature modes.");
if(allFeatureConfigs != null) {
allFeatureConfigs.forEach(featureConfig -> {
List<String> modes = new ArrayList<>();
featureConfig.getAvailableModes().forEach(featureMode -> modes.add(featureMode.getKey()));
featureModes.put(featureConfig.getFeature().getKey(), modes);
});
}
}
}

View File

@@ -289,11 +289,13 @@ public class PostTargetServiceBean implements PostTargetService {
public List<String> getPostTargetsOfEnabledFeatures(AServer server) {
List<String> postTargets = new ArrayList<>();
List<FeatureConfig> allFeatureConfigs = featureConfigService.getAllFeatureConfigs();
allFeatureConfigs.forEach(featureConfig -> {
if (featureFlagService.isFeatureEnabled(featureConfig, server)) {
featureConfig.getRequiredPostTargets().forEach(postTargetEnum -> postTargets.add(postTargetEnum.getKey()));
}
});
if(allFeatureConfigs != null) {
allFeatureConfigs.forEach(featureConfig -> {
if (featureFlagService.isFeatureEnabled(featureConfig, server)) {
featureConfig.getRequiredPostTargets().forEach(postTargetEnum -> postTargets.add(postTargetEnum.getKey()));
}
});
}
return postTargets;
}

View File

@@ -3,7 +3,7 @@
<parent>
<groupId>dev.sheldan.abstracto.core</groupId>
<artifactId>core</artifactId>
<version>1.5.17</version>
<version>1.5.19</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>

Some files were not shown because too many files have changed in this diff Show More