Compare commits

...

42 Commits

Author SHA1 Message Date
Sheldan
efd6c23713 [maven-release-plugin] prepare release abstracto-application-1.3.3 2021-07-14 02:17:48 +02:00
Sheldan
794fc7ceac [AB-71] adding very simple anti raid feature to automatically mute member who mass mention users 2021-07-14 01:48:53 +02:00
Sheldan
6b5a255aa8 [maven-release-plugin] prepare for next development iteration 2021-07-13 01:19:43 +02:00
Sheldan
620ef0708a [maven-release-plugin] prepare release abstracto-application-1.3.2 2021-07-13 01:19:35 +02:00
Sheldan
3564075e7f [AB-xxx] fixing javadoc build 2021-07-13 01:13:58 +02:00
Sheldan
de5ac0e3f4 [maven-release-plugin] prepare for next development iteration 2021-07-13 00:56:29 +02:00
Sheldan
419ac3f994 [maven-release-plugin] prepare release abstracto-application-1.3.1 2021-07-13 00:56:20 +02:00
Sheldan
ac605e4791 [AB-303] adding scheduled configurable activity updates 2021-07-13 00:35:15 +02:00
Sheldan
c7514a6bad [AB-64] adding voice context channel feature 2021-07-12 00:56:15 +02:00
Sheldan
7e7591a4b3 [AB-302] refactoring assignable roles to use buttons instead of reactions
moved button related services to component service instead of message service
adding component type to component payload
renamed async role service methods
ignoring bot reactions in starboard
fixing rank not showing correct experience to next level for other members
2021-07-11 19:05:53 +02:00
Sheldan
c08134a150 [maven-release-plugin] prepare for next development iteration 2021-07-04 13:39:29 +02:00
Sheldan
c26bcc9a66 [maven-release-plugin] prepare release abstracto-application-1.3.0 2021-07-04 13:39:22 +02:00
Sheldan
bc276c0b12 [AB-299] fixing incorrect handling of ban notifications 2021-07-04 13:00:36 +02:00
Sheldan
18929c9a01 [AB-298] fixing various issues related to modmail:
fixing editing a message without messages but only embeds not possible in channel service
refactoring closing parameters to use an object instead of parameters always
adding a progress indicator to closing a modmail thread
adding a notification to contact in order to show where the thread was created
fixing configuration for category (this caused the setup to fail, because there was no default value) and threadMessage feature modes not being correct
refactored model for closing header and added additional information
refactored modmail message logging to use the message history instead of individually loading the messages
adding nicer exception in case the mod mail message update failed
adding creation of AUserInAServer in case the user did not interact on the server yet
changed ID of modmail thread to be identical to the channel it was created in, this is so we can load the channel easier
2021-07-04 12:14:04 +02:00
Sheldan
61eefd53c3 [AB-296] adding support for buttons
adding buttons for message embed via feature mode
2021-07-03 10:40:27 +02:00
Sheldan
bbc5918d88 [AB-xxx] upgrading to newer JDA version 2021-06-27 22:47:10 +02:00
Sheldan
67121b318d [AB-271] fixing tests 2021-06-27 19:57:38 +02:00
Sheldan
5a35137132 [AB-271] limiting certain arguments for commands to require the same server 2021-06-27 17:07:01 +02:00
Sheldan
e655adf95e [AB-295] adding hard limitations for field values, names, embed description and additional message lengths 2021-06-27 16:05:40 +02:00
Sheldan
ebf659fb14 [maven-release-plugin] prepare for next development iteration 2021-06-27 00:45:18 +02:00
Sheldan
8ef236ba19 [maven-release-plugin] prepare release abstracto-application-1.2.17 2021-06-27 00:45:09 +02:00
Sheldan
7e2477a321 [AB-xxx] adding support for automatic setup steps
reducing eventwaiter threads
adding abstracto templated exception
adding json validation service
increasing threads for scheduling
adding convenience method to retrieve users
2021-06-27 00:20:15 +02:00
Sheldan
942a20700e [AB-294] fixing test 2021-06-21 21:51:12 +02:00
Sheldan
0d25b9c384 [AB-294] fixing unmuting not cached members
adding logging and catches for unbanned listener
2021-06-21 21:47:23 +02:00
Sheldan
d5f572262f [AB-287] fixing members not being available breaking warning display converter 2021-06-09 12:56:01 +02:00
Sheldan
2c3b5fb651 [AB-290] fixing showing wrong active warning count in warn decay notification
fixing un mute log failing to render in case the mute did not come from a message
fixing notification failing with exception in case there were no warnings to decay
2021-06-09 12:18:36 +02:00
Sheldan
ba4d8f1da6 [AB-293] fixing wrong emote for 18 character 2021-06-09 12:02:37 +02:00
Sheldan
cd625a8907 [AB-292] fixing post target for suggestion reminder 2021-06-09 11:58:59 +02:00
Sheldan
51a835df06 [maven-release-plugin] prepare for next development iteration 2021-06-02 12:50:09 +02:00
Sheldan
78e226aa4c [maven-release-plugin] prepare release abstracto-application-1.2.16 2021-06-02 12:49:59 +02:00
Sheldan
82281cbd6c [AB-285] fixing interval of warn decay job
removing has example config from unban
enabling to change the configuration for cron scheduler job
adding HTTP method to okhttp logger
fixing unmute job parameters
changing to use cache when retrieving reactions for a message to cache it
2021-06-02 12:27:10 +02:00
Sheldan
432dc0ffae [maven-release-plugin] prepare for next development iteration 2021-06-02 00:45:59 +02:00
Sheldan
89a3afd10e [maven-release-plugin] prepare release abstracto-application-1.2.15 2021-06-02 00:45:51 +02:00
Sheldan
793a1c3657 [AB-284] resizing warn length and changing default date behaviour for mute 2021-06-02 00:36:36 +02:00
Sheldan
7fdb87ef1f [AB-284] adding warn decay notification
adding default mute reason
fixing incorrect muting user being stored
2021-06-01 23:38:06 +02:00
Sheldan
2f8e7c3947 [AB-282] adding okhttp interceptor to log requests 2021-06-01 21:44:03 +02:00
Sheldan
3bf761a2e5 [AB-281] adding ban and unban command
removing banId command in favor of the normal ban command
removing various feature modes for moderation for clearer configuration
2021-06-01 21:10:17 +02:00
Sheldan
55e0879e06 [AB-277] adding report mechanism via reactions 2021-05-30 21:00:49 +02:00
Sheldan
d69f597663 [AB-279] extending max level for experience gain to 150 2021-05-30 20:00:06 +02:00
Sheldan
148c25da4c [AB-275] fixing channel groups not being able to be found, because of upper/lowercase
adding performance improvements for experience listener
adding logging to when a user gains a level
fixing creating a user experience instance in the join listener, which was not persisted
2021-05-29 01:09:14 +02:00
Sheldan
f3bb9b9a69 [AB-276] enabling to cache more members in JDA to reduce requests 2021-05-29 00:56:02 +02:00
Sheldan
0366d48764 [maven-release-plugin] prepare for next development iteration 2021-05-26 21:51:42 +02:00
494 changed files with 12509 additions and 3577 deletions

View File

@@ -14,7 +14,7 @@ An example implementation of this bot can be seen [here](https://github.com/Shel
## Technologies
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 4.2.1_262
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 4.3.0_284
* [Spring boot](https://github.com/spring-projects/spring-boot) is used as a framework to create standalone application in Java with Java EE methods. (including Dependency injection and more)
* [Hibernate](https://github.com/hibernate/hibernate-orm) is used as a reference implementation of JPA.
* [Freemarker](https://github.com/apache/freemarker) is used as a templating engine. This is used to provide internationalization for user facing text and enable dynamic embed configuration.

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.3.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>anti-raid-impl</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>dev.sheldan.abstracto.core</groupId>
<artifactId>core-int</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>anti-raid-int</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/liquibase.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,18 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
<id>liquibase</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<outputDirectory>.</outputDirectory>
<directory>${project.basedir}/src/main/resources/migrations</directory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.antiraid.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:antiRaid-config.properties")
public class AntiRaidProperties {
}

View File

@@ -0,0 +1,36 @@
package dev.sheldan.abstracto.antiraid.listener;
import dev.sheldan.abstracto.antiraid.config.AntiRaidFeatureDefinition;
import dev.sheldan.abstracto.antiraid.service.MassPingService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener;
import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.ChannelType;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class MassPingMessageListener implements AsyncMessageReceivedListener {
@Autowired
private MassPingService massPingService;
@Override
public DefaultListenerResult execute(MessageReceivedModel model) {
Message message = model.getMessage();
if(message.getAuthor().isBot() || message.isWebhookMessage() || !message.isFromGuild() || !message.isFromType(ChannelType.TEXT)) {
return DefaultListenerResult.IGNORED;
}
massPingService.processMessage(message);
return DefaultListenerResult.PROCESSED;
}
@Override
public FeatureDefinition getFeature() {
return AntiRaidFeatureDefinition.ANTI_RAID;
}
}

View File

@@ -0,0 +1,109 @@
package dev.sheldan.abstracto.antiraid.service;
import dev.sheldan.abstracto.antiraid.config.AntiRaidPostTarget;
import dev.sheldan.abstracto.antiraid.model.MassPingNotificationModel;
import dev.sheldan.abstracto.core.models.ConditionContextInstance;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import dev.sheldan.abstracto.core.service.ConditionService;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
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.moderation.service.MuteService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class MassPingServiceBean implements MassPingService {
private static final String MASS_PING_MUTE_NOTIFICATION_TEMPLATE_KEY = "massPing_mute_notification";
private static final String LEVEL_CONDITION_NAME = "HAS_LEVEL";
private static final String LEVEL_CONDITION_USER_ID_PARAMETER = "userId";
private static final String LEVEL_CONDITION_LEVEL_PARAMETER = "level";
@Autowired
private ConfigService configService;
@Autowired
private MuteService muteService;
@Autowired
private TemplateService templateService;
@Autowired
private MassPingServiceBean self;
@Autowired
private PostTargetService postTargetService;
@Autowired
private ConditionService conditionService;
@Value("${abstracto.massPing.maxAllowedMentions}")
private Integer maxAllowedMentions;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Override
public CompletableFuture<Void> processMessage(Message message) {
if(message.getMentionedMembers().size() > maxAllowedMentions) {
Integer level = configService.getLongValueOrConfigDefault(MassPingService.MAX_AFFECTED_LEVEL_KEY, message.getGuild().getIdLong()).intValue();
boolean allowed = allowedToMassMention(message, level);
if(!allowed) {
return muteService.muteMemberWithoutContext(message.getMember())
.thenAccept(unused -> self.sendMassPingMuteNotification(message))
.thenAccept(unused -> log.info("Muted member {} in server {} because of too many member mentions. (> {}).",
message.getMember().getIdLong(), message.getGuild().getIdLong(), maxAllowedMentions));
} else {
log.info("User {} in server {} is allowed to mass mention, because of level (or lack of level configuration).",
message.getMember().getIdLong(), message.getGuild().getIdLong());
return CompletableFuture.completedFuture(null);
}
} else {
return CompletableFuture.completedFuture(null);
}
}
private boolean allowedToMassMention(Message message, Integer level) {
log.info("Checking if member {} is allowed to mention a lot of users in server {}.", message.getAuthor().getIdLong(), message.getGuild().getIdLong());
Map<String, Object> parameters = new HashMap<>();
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(message.getMember());
parameters.put(LEVEL_CONDITION_USER_ID_PARAMETER, userInAServer.getUserInServerId());
parameters.put(LEVEL_CONDITION_LEVEL_PARAMETER, level);
ConditionContextInstance contextInstance = ConditionContextInstance
.builder()
.conditionName(LEVEL_CONDITION_NAME)
.parameters(parameters)
.build();
return conditionService.checkConditions(contextInstance);
}
@Transactional
public CompletableFuture<Void> sendMassPingMuteNotification(Message message) {
Member member = message.getMember();
MassPingNotificationModel model = MassPingNotificationModel
.builder()
.messageLink(message.getJumpUrl())
.mentionCount(message.getMentionedMembers().size())
.messageContent(message.getContentRaw())
.memberDisplay(MemberDisplay.fromMember(member))
.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate(MASS_PING_MUTE_NOTIFICATION_TEMPLATE_KEY, model, member.getGuild().getIdLong());
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(messageToSend, AntiRaidPostTarget.MASS_PING_LOG, member.getGuild().getIdLong()));
}
}

View File

@@ -0,0 +1,9 @@
abstracto.featureFlags.antiRaid.featureName=antiRaid
abstracto.featureFlags.antiRaid.enabled=false
abstracto.postTargets.massPingLog.name=massPingLog
abstracto.massPing.maxAllowedMentions=5
abstracto.systemConfigs.massPingMinLevel.name=massPingMinLevel
abstracto.systemConfigs.massPingMinLevel.longValue=15

View File

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

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="feature.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,14 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="anti_raid-feature-insertion">
<insert tableName="feature">
<column name="key" value="antiRaid"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,9 @@
<?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" >
</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="1.3.3/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>anti-raid</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.3.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>anti-raid-int</artifactId>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>dev.sheldan.abstracto.core</groupId>
<artifactId>core-int</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>dev.sheldan.abstracto.modules</groupId>
<artifactId>moderation-int</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,39 @@
package dev.sheldan.abstracto.antiraid.config;
import dev.sheldan.abstracto.antiraid.service.MassPingService;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import dev.sheldan.abstracto.moderation.config.feature.MutingFeatureConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class AntiRaidFeatureConfig implements FeatureConfig {
@Autowired
private MutingFeatureConfig mutingFeatureConfig;
@Override
public FeatureDefinition getFeature() {
return AntiRaidFeatureDefinition.ANTI_RAID;
}
@Override
public List<PostTargetEnum> getRequiredPostTargets() {
return Arrays.asList(AntiRaidPostTarget.MASS_PING_LOG);
}
@Override
public List<String> getRequiredSystemConfigKeys() {
return Arrays.asList(MassPingService.MAX_AFFECTED_LEVEL_KEY);
}
@Override
public List<FeatureConfig> getRequiredFeatures() {
return Arrays.asList(mutingFeatureConfig);
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.antiraid.config;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import lombok.Getter;
@Getter
public enum AntiRaidFeatureDefinition implements FeatureDefinition {
ANTI_RAID("antiRaid");
private String key;
AntiRaidFeatureDefinition(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.antiraid.config;
import dev.sheldan.abstracto.core.config.PostTargetEnum;
import lombok.Getter;
@Getter
public enum AntiRaidPostTarget implements PostTargetEnum {
MASS_PING_LOG("massPingLog");
private String key;
AntiRaidPostTarget(String key) {
this.key = key;
}
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.antiraid.model;
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class MassPingNotificationModel {
private MemberDisplay memberDisplay;
private String messageContent;
private String messageLink;
private Integer mentionCount;
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.antiraid.service;
import net.dv8tion.jda.api.entities.Message;
import java.util.concurrent.CompletableFuture;
public interface MassPingService {
String MAX_AFFECTED_LEVEL_KEY = "massPingMinLevel";
CompletableFuture<Void> processMessage(Message message);
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>abstracto-modules</artifactId>
<groupId>dev.sheldan.abstracto.modules</groupId>
<version>1.3.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>anti-raid</artifactId>
<packaging>pom</packaging>
<modules>
<module>anti-raid-int</module>
<module>anti-raid-impl</module>
</modules>
</project>

View File

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

View File

@@ -16,6 +16,7 @@ import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* Command used to activate an {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
@@ -30,23 +31,24 @@ public class ActivateAssignableRolePlace extends AbstractConditionableCommand {
private ServerManagementService serverManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
AServer server = serverManagementService.loadServer(commandContext.getGuild());
service.activateAssignableRolePlace(server, name);
return CommandResult.fromSuccess();
return service.activateAssignableRolePlace(server, name)
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(rolePostName);
Parameter placeName = Parameter.builder().name("name").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(placeName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("activateAssignableRolePlace")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -1,7 +1,8 @@
package dev.sheldan.abstracto.assignableroles.command;
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleConditionService;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
@@ -9,52 +10,44 @@ 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.models.FullEmote;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import net.dv8tion.jda.api.entities.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
/**
* Command used to set the position of one individual {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole assignableRole}
* within an {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
*/
@Component
public class SetAssignableRolePosition extends AbstractConditionableCommand {
public class AddAssignableRoleCondition extends AbstractConditionableCommand {
@Autowired
private AssignableRolePlaceService service;
@Autowired
private ServerManagementService serverManagementService;
private AssignableRoleConditionService assignableRoleConditionService;
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
FullEmote emote = (FullEmote) parameters.get(1);
Integer newPosition = (Integer) parameters.get(2);
AServer server = serverManagementService.loadServer(commandContext.getGuild());
service.setEmoteToPosition(server, name, emote, newPosition);
Role role = (Role) parameters.get(1);
AssignableRoleConditionType configKey = (AssignableRoleConditionType) parameters.get(2);
String parameterValue = (String) parameters.get(3);
assignableRoleConditionService.createAssignableRoleCondition(name, role, configKey, parameterValue);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter emote = Parameter.builder().name("emote").type(FullEmote.class).templated(true).build();
Parameter newPosition = Parameter.builder().name("newPosition").type(Integer.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(rolePostName, emote, newPosition);
Parameter placeName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter role = Parameter.builder().name("role").type(Role.class).templated(true).build();
Parameter conditionKey = Parameter.builder().name("conditionKey").type(AssignableRoleConditionType.class).templated(true).build();
Parameter conditionValue = Parameter.builder().name("conditionParameter").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(placeName, role, conditionKey, conditionValue);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("setAssignableRolePosition")
.name("addAssignableRoleCondition")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.causesReaction(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();

View File

@@ -1,7 +1,6 @@
package dev.sheldan.abstracto.assignableroles.command;
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRoleAlreadyDefinedException;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRoleNotUsableException;
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
@@ -12,10 +11,10 @@ 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.models.FullEmote;
import dev.sheldan.abstracto.core.models.FullRole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import net.dv8tion.jda.api.entities.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -43,27 +42,31 @@ public class AddRoleToAssignableRolePost extends AbstractConditionableCommand {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
FullEmote emote = (FullEmote) parameters.get(1);
String description = (String) parameters.get(2);
FullRole role = (FullRole) parameters.get(3);
Role role = (Role) parameters.get(1);
String description = null;
if (parameters.size() > 2) {
description = (String) parameters.get(2);
}
FullEmote emote = null;
if(parameters.size() > 3) {
emote = (FullEmote) parameters.get(3);
}
AServer server = serverManagementService.loadServer(commandContext.getGuild());
if(service.hasAssignableRolePlaceEmote(server, name, emote.getFakeEmote())) {
throw new AssignableRoleAlreadyDefinedException(emote, name);
// already used check via role and assignable role place name
if(!roleService.canBotInteractWithRole(role)) {
throw new AssignableRoleNotUsableException(role);
}
if(!roleService.canBotInteractWithRole(role.getRole())) {
throw new AssignableRoleNotUsableException(role, commandContext.getGuild());
}
return service.addRoleToAssignableRolePlace(server, name, role.getRole(), emote, description)
return service.addRoleToAssignableRolePlace(server, name, role, emote, description)
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter emote = Parameter.builder().name("emote").type(FullEmote.class).templated(true).build();
Parameter description = Parameter.builder().name("description").type(String.class).templated(true).build();
Parameter role = Parameter.builder().name("role").type(FullRole.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(rolePostName, emote, description, role);
Parameter placeName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter role = Parameter.builder().name("role").type(Role.class).templated(true).build();
Parameter rolePostName = Parameter.builder().name("displayText").type(String.class).templated(true).build();
Parameter emote = Parameter.builder().name("emote").type(FullEmote.class).optional(true).templated(true).build();
List<Parameter> parameters = Arrays.asList(placeName, role, rolePostName, emote);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("addRoleToAssignableRolePlace")

View File

@@ -39,7 +39,7 @@ public class ChangeAssignableRolePlaceConfig extends AbstractConditionableComman
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
AssignableRolePlaceParameterKey configKey = (AssignableRolePlaceParameterKey) parameters.get(1);
Object parameterValue = parameters.get(2);
String parameterValue = (String) parameters.get(2);
AServer server = serverManagementService.loadServer(commandContext.getGuild());
return service.changeConfiguration(server, name, configKey, parameterValue)
.thenApply(aVoid -> CommandResult.fromSuccess());
@@ -49,7 +49,7 @@ public class ChangeAssignableRolePlaceConfig extends AbstractConditionableComman
public CommandConfiguration getConfiguration() {
Parameter assignableRolePlaceName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter parameterKey = Parameter.builder().name("key").type(AssignableRolePlaceParameterKey.class).templated(true).build();
Parameter parameterValue = Parameter.builder().name("value").type(Object.class).templated(true).build();
Parameter parameterValue = Parameter.builder().name("value").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(assignableRolePlaceName, parameterKey, parameterValue);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();

View File

@@ -12,6 +12,7 @@ import dev.sheldan.abstracto.core.command.config.validator.MaxStringLengthValida
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.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
@@ -40,6 +41,9 @@ public class CreateAssignableRolePost extends AbstractConditionableCommand {
String name = (String) parameters.get(0);
TextChannel channel = (TextChannel) parameters.get(1);
String text = (String) parameters.get(2);
if(!channel.getGuild().equals(commandContext.getGuild())) {
throw new EntityGuildMismatchException();
}
AChannel chosenChannel = channelManagementService.loadChannel(channel.getIdLong());
service.createAssignableRolePlace(name, chosenChannel, text);
return CommandResult.fromSuccess();

View File

@@ -16,6 +16,7 @@ import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* Command used to deactive an {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
@@ -30,12 +31,12 @@ public class DeactivateAssignableRolePlace extends AbstractConditionableCommand
private ServerManagementService serverManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
AServer server = serverManagementService.loadServer(commandContext.getGuild());
service.deactivateAssignableRolePlace(server, name);
return CommandResult.fromSuccess();
return service.deactivateAssignableRolePlace(server, name)
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
@@ -47,6 +48,7 @@ public class DeactivateAssignableRolePlace extends AbstractConditionableCommand
.name("deactivateAssignableRolePlace")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)

View File

@@ -9,6 +9,8 @@ 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.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired;
@@ -16,6 +18,7 @@ import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* Command used to move an {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
@@ -31,12 +34,16 @@ public class MoveAssignableRolePlace extends AbstractConditionableCommand {
private ServerManagementService serverManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
TextChannel newChannel = (TextChannel) parameters.get(1);
placeManagementService.moveAssignableRolePlace(name, newChannel);
return CommandResult.fromSuccess();
if(!newChannel.getGuild().equals(commandContext.getGuild())) {
throw new EntityGuildMismatchException();
}
AServer server = serverManagementService.loadServer(commandContext.getGuild());
return placeManagementService.moveAssignableRolePlace(server, name, newChannel)
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
@@ -50,6 +57,7 @@ public class MoveAssignableRolePlace extends AbstractConditionableCommand {
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.causesReaction(true)
.async(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)

View File

@@ -1,7 +1,8 @@
package dev.sheldan.abstracto.assignableroles.command;
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleConditionService;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
@@ -9,49 +10,42 @@ 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.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import net.dv8tion.jda.api.entities.Role;
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;
/**
* Command used to show how an {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
* would look like in the current {@link net.dv8tion.jda.api.entities.TextChannel channel}
*/
@Component
public class TestAssignableRolePlace extends AbstractConditionableCommand {
public class RemoveAssignableRoleCondition extends AbstractConditionableCommand {
@Autowired
private AssignableRolePlaceService service;
@Autowired
private ServerManagementService serverManagementService;
private AssignableRoleConditionService assignableRoleConditionService;
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
AServer server = serverManagementService.loadServer(commandContext.getGuild());
return service.testAssignableRolePlace(server, name, commandContext.getChannel())
.thenApply(aVoid -> CommandResult.fromIgnored());
Role role = (Role) parameters.get(1);
AssignableRoleConditionType configKey = (AssignableRoleConditionType) parameters.get(2);
assignableRoleConditionService.deleteAssignableRoleCondition(name, role, configKey);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(rolePostName);
Parameter placeName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter role = Parameter.builder().name("role").type(Role.class).templated(true).build();
Parameter conditionKey = Parameter.builder().name("conditionKey").type(AssignableRoleConditionType.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(placeName, role, conditionKey);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("testAssignableRolePlace")
.name("removeAssignableRoleCondition")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.causesReaction(true)
.async(true)
.supportsEmbedException(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();

View File

@@ -9,7 +9,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.models.FullEmote;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -36,17 +36,17 @@ public class RemoveRoleFromAssignableRolePlace extends AbstractConditionableComm
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
FullEmote emote = (FullEmote) parameters.get(1);
ARole role = (ARole) parameters.get(1);
AServer server = serverManagementService.loadServer(commandContext.getGuild());
return service.removeRoleFromAssignableRolePlace(server, name, emote)
return service.removeRoleFromAssignableRolePlace(server, name, role)
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter emote = Parameter.builder().name("emote").type(FullEmote.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(rolePostName, emote);
Parameter role = Parameter.builder().name("role").type(ARole.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(rolePostName, role);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("removeRoleFromAssignableRolePlace")

View File

@@ -1,81 +0,0 @@
package dev.sheldan.abstracto.assignableroles.command;
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
import dev.sheldan.abstracto.assignableroles.exception.EmoteNotInAssignableRolePlaceException;
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService;
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.models.FullEmote;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
/**
* Command used to swap the positions of two {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole roles}
* within one {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
*/
@Component
public class SwapAssignableRolePosition extends AbstractConditionableCommand {
@Autowired
private AssignableRolePlaceService service;
@Autowired
private EmoteService emoteService;
@Autowired
private ServerManagementService serverManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0);
FullEmote firstEmote = (FullEmote) parameters.get(1);
FullEmote secondEmote = (FullEmote) parameters.get(2);
AServer server = serverManagementService.loadServer(commandContext.getGuild());
if(emoteService.compareAEmote(firstEmote.getFakeEmote(), secondEmote.getFakeEmote())) {
return CommandResult.fromError("You cannot swap the same emote");
}
if(!service.hasAssignableRolePlaceEmote(server, name, firstEmote.getFakeEmote())) {
throw new EmoteNotInAssignableRolePlaceException(firstEmote, name);
}
if(!service.hasAssignableRolePlaceEmote(server, name, firstEmote.getFakeEmote())) {
throw new EmoteNotInAssignableRolePlaceException(secondEmote, name);
}
service.swapPositions(server, name, firstEmote, secondEmote);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
Parameter firstEmote = Parameter.builder().name("firstEmote").type(FullEmote.class).templated(true).build();
Parameter secondEmote = Parameter.builder().name("secondEmote").type(FullEmote.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(rolePostName, firstEmote, secondEmote);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("swapAssignableRolePosition")
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
.templated(true)
.causesReaction(true)
.supportsEmbedException(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
@Override
public FeatureDefinition getFeature() {
return AssignableRoleFeatureDefinition.ASSIGNABLE_ROLES;
}
}

View File

@@ -0,0 +1,87 @@
package dev.sheldan.abstracto.assignableroles.condition;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleMinLevelModel;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRolePlaceConditionModel;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleMinLevelResult;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRoleCondition;
import dev.sheldan.abstracto.assignableroles.model.template.condition.AssignableRoleConditionDisplay;
import dev.sheldan.abstracto.assignableroles.model.template.condition.AssignableRoleMinLevelDisplay;
import dev.sheldan.abstracto.core.models.ConditionContextInstance;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.template.display.RoleDisplay;
import dev.sheldan.abstracto.core.service.ConditionService;
import net.dv8tion.jda.api.entities.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class AssignableRoleMinimumLevelConditionImpl implements AssignableRoleConditionEvaluator {
private final String conditionName = "HAS_LEVEL";
private final String userIdParameter = "userId";
private final String levelParameter = "level";
@Autowired
private ConditionService conditionService;
@Override
public boolean fulfillsCondition(AssignableRoleCondition conditionDefinition, AUserInAServer aUserInAServer) {
Integer level = parseLevel(conditionDefinition);
Map<String, Object> parameters = new HashMap<>();
parameters.put(userIdParameter, aUserInAServer.getUserInServerId());
parameters.put(levelParameter, level);
ConditionContextInstance contextInstance = ConditionContextInstance
.builder()
.conditionName(conditionName)
.parameters(parameters)
.build();
return conditionService.checkConditions(contextInstance);
}
@Override
public boolean usableValue(String value) {
try {
parseLevelValue(value);
return true;
} catch (Exception exception) {
return false;
}
}
private Integer parseLevel(AssignableRoleCondition conditionDefinition) {
return parseLevelValue(conditionDefinition.getConditionValue());
}
private int parseLevelValue(String value) {
return Integer.parseInt(value);
}
@Override
public AssignableRolePlaceConditionModel createNotificationModel(AssignableRoleCondition conditionDefinition, Role role) {
Integer level = parseLevel(conditionDefinition);
AssignableRoleMinLevelModel model = AssignableRoleMinLevelModel
.builder()
.minLevel(level)
.roleDisplay(RoleDisplay.fromRole(role))
.build();
return AssignableRoleMinLevelResult
.builder()
.model(model)
.build();
}
@Override
public AssignableRoleConditionDisplay getConditionDisplay(AssignableRoleCondition conditionDefinition) {
return new AssignableRoleMinLevelDisplay(Integer.parseInt(conditionDefinition.getConditionValue()));
}
@Override
public boolean handlesCondition(AssignableRoleConditionType type) {
return AssignableRoleConditionType.MIN_LEVEL.equals(type);
}
}

View File

@@ -1,47 +0,0 @@
package dev.sheldan.abstracto.assignableroles.listener;
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageDeletedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.listener.MessageDeletedModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class AssignablePostDeletedListener implements AsyncMessageDeletedListener {
@Autowired
private AssignableRolePlacePostManagementService service;
@Override
public FeatureDefinition getFeature() {
return AssignableRoleFeatureDefinition.ASSIGNABLE_ROLES;
}
/**
* This method deletes one individual {@link AssignableRolePlacePost post}, because its message has been deleted
* @param model The {@link MessageDeletedModel message} containing the {@link CachedMessage cachedMessage} which was deleted
*/
@Override
public DefaultListenerResult execute(MessageDeletedModel model) {
Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(model.getCachedMessage().getMessageId());
messageOptional.ifPresent(post -> {
AssignableRolePlace assignablePlace = post.getAssignablePlace();
log.info("Post {} has been deleted in server {} in channel {}, we are removing a post from place {}.",
post.getId(), model.getServerId(), model.getCachedMessage().getChannelId(), assignablePlace.getKey());
post.getAssignableRoles().forEach(assignableRole -> assignableRole.setAssignableRolePlacePost(null));
assignablePlace.getMessagePosts().remove(post);
});
return DefaultListenerResult.PROCESSED;
}
}

View File

@@ -1,175 +0,0 @@
package dev.sheldan.abstracto.assignableroles.listener;
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService;
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleServiceBean;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRoleManagementService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlaceManagementService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionAddedListener;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.cache.CachedReaction;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.listener.ReactionAddedModel;
import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.MemberService;
import dev.sheldan.abstracto.core.service.ReactionService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.MessageReaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AssignablePostReactionAdded implements AsyncReactionAddedListener {
@Autowired
private AssignableRolePlacePostManagementService service;
@Autowired
private AssignableRoleServiceBean assignableRoleServiceBean;
@Autowired
private EmoteService emoteService;
@Autowired
private AssignableRolePlaceService assignableRolePlaceService;
@Autowired
private AssignedRoleUserManagementService assignedRoleUserManagementService;
@Autowired
private AssignableRolePlaceManagementService assignableRolePlaceManagementService;
@Autowired
private AssignablePostReactionAdded self;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private AssignableRoleManagementService assignableRoleManagementService;
@Autowired
private ReactionService reactionService;
@Autowired
private MemberService memberService;
/**
* Iterates over all {@link AssignableRole assignableRoles} of the post and checks which {@link AssignableRole assignableRole}
* is identified by the added {@link MessageReaction reaction}. If there is no valid reaction, the {@link net.dv8tion.jda.api.entities.MessageReaction reaction}
* will be removed again. In case the {@link AssignableRolePlace place} is configured to have unique roles, this will remove the existing
* {@link net.dv8tion.jda.api.entities.MessageReaction reaction} and the assigned {@link net.dv8tion.jda.api.entities.Role role}.
* Afterwards the appropriate {@link net.dv8tion.jda.api.entities.Role role} will be added and the update
* will be stored in the database.
* @param assignablePlacePost The {@link AssignableRolePlacePost post} onto which the {@link MessageReaction reaction} was added to
* @param model The {@link ReactionAddedModel model} containing information about who added which reaction where
*/
private void addAppropriateRoles(AssignableRolePlacePost assignablePlacePost, ReactionAddedModel model) {
boolean validReaction = false;
AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (AssignableRole assignableRole : assignablePlacePost.getAssignableRoles()) {
log.debug("Checking emote {} if it was reaction for assignable role place.", assignableRole.getEmote().getId());
if (emoteService.isReactionEmoteAEmote(model.getReaction().getReactionEmote(), assignableRole.getEmote())) {
if(assignableRolePlace.getUniqueRoles()) {
log.debug("Assignable role place {} has unique roles configured. Removing existing reactions and roles.", assignableRolePlace.getId());
Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(model.getUserReacting());
byUserInServer.ifPresent(user -> futures.add(assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, user)));
}
Long assignableRoleId = assignableRole.getId();
log.info("User added {} reaction {} and gets assignable role {} in server {}.", model.getUserReacting().getUserId(), assignableRole.getEmote().getId(), assignableRoleId, model.getServerId());
CompletableFuture<Void> roleAdditionFuture = assignableRoleServiceBean.assignAssignableRoleToUser(assignableRoleId, model.getUserReacting());
futures.add(CompletableFuture.allOf(roleAdditionFuture));
validReaction = true;
break;
}
}
if(!validReaction) {
log.debug("Reaction was not found in the configuration of assignable role place {}, removing reaction.", assignableRolePlace.getId());
futures.add(reactionService.removeReactionFromMessage(model.getReaction(), model.getMessage(), model.getMemberReacting().getUser()));
}
Long assignableRolePlaceId = assignableRolePlace.getId();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid ->
self.updateStoredAssignableRoles(assignableRolePlaceId, model.getUserReacting(), model.getReaction())
).exceptionally(throwable -> {
log.error("Failed to add role or remove emote for assignable role place {}.", assignableRolePlaceId, throwable);
return null;
});
}
/**
* Persists the {@link AssignableRole role} changes for the user who added a reaction in the database
* @param assignableRolePlaceId The ID of the {@link AssignableRolePlace place}
* @param serverUser The {@link ServerUser serverUser} who added the {@link net.dv8tion.jda.api.entities.MessageReaction reaction}
* @param reaction The {@link CachedReaction reaction} wich was added
*/
@Transactional
public void updateStoredAssignableRoles(Long assignableRolePlaceId, ServerUser serverUser, MessageReaction reaction) {
AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(assignableRolePlaceId);
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(serverUser);
if(place.getUniqueRoles()) {
log.debug("Assignable role place {} has unique roles. Deleting all existing references.", assignableRolePlaceId);
assignableRoleServiceBean.clearAllRolesOfUserInPlace(place, userInAServer);
}
AssignableRole role = assignableRoleManagementService.getRoleForReactionEmote(reaction.getReactionEmote(), place);
log.info("Adding role to assignable role {} to user {} in server {}.", role.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
assignableRoleServiceBean.addRoleToUser(role.getId(), userInAServer);
}
@Override
public FeatureDefinition getFeature() {
return AssignableRoleFeatureDefinition.ASSIGNABLE_ROLES;
}
/**
* Determines if the {@link net.dv8tion.jda.api.entities.Message message} a reaction was added to, belongs to a
* {@link AssignableRolePlacePost post}.
* If the {@link AssignableRolePlacePost post} belong to an inactive {@link AssignableRolePlace place} this method
* will automatically remove the reaction, self reactions are ignored. Otherwise the logic according to the configuration
* of the {@link AssignableRolePlace place} will be executed.
* @param model The {@link ReactionAddedModel message} which contains information about the added reaction
*/
@Override
public DefaultListenerResult execute(ReactionAddedModel model) {
MessageReaction reaction = model.getReaction();
Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(model.getMessage().getMessageId());
if(messageOptional.isPresent()) {
AssignableRolePlacePost assignablePlacePost = messageOptional.get();
if(reaction.isSelf()) {
log.info("Ignoring self reaction on assignable role post in server {}.", model.getServerId());
return DefaultListenerResult.IGNORED;
}
Long assignableRolePlacePostId = assignablePlacePost.getId();
if(assignablePlacePost.getAssignablePlace().getActive()) {
log.info("User {} added reaction to assignable role place {} in server {}. Handling added event.", model.getUserReacting().getUserId(), assignablePlacePost.getId(), model.getServerId());
addAppropriateRoles(assignablePlacePost, model);
} else {
reactionService.removeReactionFromMessage(model.getReaction(), model.getMessage()).exceptionally(throwable -> {
log.error("Failed to remove reaction on place post {} because place is inactive.", assignableRolePlacePostId, throwable);
return null;
});
log.debug("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), model.getServerId());
}
}
return DefaultListenerResult.PROCESSED;
}
}

View File

@@ -1,81 +0,0 @@
package dev.sheldan.abstracto.assignableroles.listener;
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlacePostManagementService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncReactionRemovedListener;
import dev.sheldan.abstracto.core.models.cache.CachedMessage;
import dev.sheldan.abstracto.core.models.listener.ReactionRemovedModel;
import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class AssignablePostReactionRemoved implements AsyncReactionRemovedListener {
@Autowired
private AssignableRolePlacePostManagementService service;
@Autowired
private EmoteService emoteService;
@Autowired
private RoleService roleService;
@Autowired
private AssignableRoleService assignableRoleService;
@Override
public FeatureDefinition getFeature() {
return AssignableRoleFeatureDefinition.ASSIGNABLE_ROLES;
}
/**
* Determines if the {@link net.dv8tion.jda.api.entities.Message message} a reaction was removed from, belongs to a
* {@link AssignableRolePlacePost post}.
* If the {@link AssignableRolePlacePost post} belong to an inactive {@link AssignableRolePlace place} this method ignores the removal.
* Otherwise the logic according to the configuration
* of the {@link AssignableRolePlace place} will be executed.
* @param model The {@link ReactionRemovedModel model} containing the information which reaction was placed where
*/
@Override
public DefaultListenerResult execute(ReactionRemovedModel model) {
CachedMessage message = model.getMessage();
Optional<AssignableRolePlacePost> messageOptional = service.findByMessageIdOptional(message.getMessageId());
if(messageOptional.isPresent()) {
AssignableRolePlacePost assignablePlacePost = messageOptional.get();
if(assignablePlacePost.getAssignablePlace().getActive()) {
assignablePlacePost.getAssignableRoles().forEach(assignableRole -> {
if(emoteService.isReactionEmoteAEmote(model.getReaction().getReactionEmote(), assignableRole.getEmote())) {
Long assignableRoleId = assignableRole.getId();
log.info("Removing assignable role {} for user {} in server {} from assignable role place {}.", assignableRoleId,
model.getUserRemoving().getUserId(), model.getServerId(), assignablePlacePost.getAssignablePlace().getId());
assignableRoleService.fullyRemoveAssignableRoleFromUser(assignableRole, model.getUserRemoving()).exceptionally(throwable -> {
log.error("Failed to remove assignable role {} from user {} in server {}.", assignableRoleId, model.getUserRemoving().getUserId(), model.getServerId(), throwable);
return null;
});
}
});
return DefaultListenerResult.PROCESSED;
} else {
log.debug("Reaction for assignable place {} in sever {} was added, but place is inactive.", assignablePlacePost.getAssignablePlace().getKey(), model.getServerId());
return DefaultListenerResult.PROCESSED;
}
} else {
return DefaultListenerResult.IGNORED;
}
}
}

View File

@@ -0,0 +1,217 @@
package dev.sheldan.abstracto.assignableroles.listener;
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRoleNotFoundException;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionResult;
import dev.sheldan.abstracto.assignableroles.model.AssignableRolePlacePayload;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRolePlaceConditionModel;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
import dev.sheldan.abstracto.assignableroles.model.template.AssignableRoleSuccessNotificationModel;
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleConditionServiceBean;
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceServiceBean;
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlaceManagementService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUserManagementServiceBean;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.config.ListenerPriority;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.listener.ButtonClickedListenerResult;
import dev.sheldan.abstracto.core.listener.async.jda.ButtonClickedListener;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.models.listener.ButtonClickedListenerModel;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
import net.dv8tion.jda.api.interactions.components.ButtonInteraction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@Component
@Slf4j
public class AssignableRoleButtonClickedListener implements ButtonClickedListener {
@Autowired
private AssignableRolePlaceManagementService assignableRolePlaceManagementService;
@Autowired
private RoleService roleService;
@Autowired
private AssignableRoleButtonClickedListener self;
@Autowired
private InteractionService interactionService;
@Autowired
private AssignableRoleService assignableRoleService;
@Autowired
private AssignedRoleUserManagementServiceBean assignedRoleUserManagementServiceBean;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private AssignableRoleConditionServiceBean assignableRoleConditionServiceBean;
@Override
public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) {
ButtonClickEvent event = model.getEvent();
AssignableRolePlacePayload payload = (AssignableRolePlacePayload) model.getDeserializedPayload();
AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(payload.getPlaceId());
if(event.getGuild() != null && event.getMember() != null) {
Guild guild = event.getGuild();
List<Role> removedRoles = new ArrayList<>();
Role roleById = guild.getRoleById(payload.getRoleId());
Optional<AssignableRole> assignableRoleOptional = place
.getAssignableRoles()
.stream()
.filter(assignableRole -> assignableRole.getRole().getId().equals(payload.getRoleId()))
.findFirst();
if(!assignableRoleOptional.isPresent()) {
throw new AssignableRoleNotFoundException(payload.getRoleId());
}
if(roleById != null) {
boolean memberHasRole = event
.getMember()
.getRoles()
.stream()
.anyMatch(memberRole -> memberRole.getIdLong() == payload.getRoleId());
if(!memberHasRole) {
AssignableRole assignableRole = assignableRoleOptional.get();
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
if(!assignableRole.getConditions().isEmpty()) {
AssignableRoleConditionResult conditionResult =
assignableRoleConditionServiceBean.evaluateConditions(assignableRole.getConditions(), aUserInAServer, roleById);
if(!conditionResult.getFulfilled()) {
self.notifyUserAboutConditionFail(model, event.getInteraction(), conditionResult.getModel());
return ButtonClickedListenerResult.ACKNOWLEDGED;
}
}
CompletableFuture<Void> removalFuture;
if(place.getUniqueRoles()) {
Optional<AssignedRoleUser> assignedRoleUserOptional = assignedRoleUserManagementServiceBean.findByUserInServerOptional(aUserInAServer);
if(assignedRoleUserOptional.isPresent()) {
AssignedRoleUser roleUser = assignedRoleUserOptional.get();
List<Role> rolesToRemove = roleUser
.getRoles()
.stream()
.filter(roleOfUser -> roleOfUser.getAssignablePlace().equals(place))
.map(roleOfUser -> guild.getRoleById(roleOfUser.getRole().getId()))
.filter(Objects::nonNull)
.collect(Collectors.toList());
removedRoles.addAll(rolesToRemove);
List<CompletableFuture<Void>> removalFutures = new ArrayList<>();
rolesToRemove.forEach(roleToRemove -> removalFutures.add(roleService.removeRoleFromUserAsync(event.getMember(), roleToRemove)));
removalFuture = new CompletableFutureList<>(removalFutures).getMainFuture();
} else {
removalFuture = CompletableFuture.completedFuture(null);
}
} else {
removalFuture = CompletableFuture.completedFuture(null);
}
CompletableFuture<Void> roleAdditionFuture = roleService.addRoleToMemberAsync(event.getMember(), roleById);
CompletableFuture.allOf(removalFuture, roleAdditionFuture).whenComplete((unused, throwable) -> {
if(throwable != null) {
log.error("Failed to either add or remove roles for assignable role place {} in server {}.", payload.getPlaceId(), guild.getIdLong());
}
if(!roleAdditionFuture.isCompletedExceptionally()) {
log.info("Added role {} to member {} in server {} for assignable role interaction {} on component {}.",
roleById.getId(), event.getMember().getId(), guild.getIdLong(), event.getInteraction().getId(), event.getComponentId());
self.notifyUser(model, true, roleById, event.getInteraction(), removedRoles).thenAccept(unused1 -> {
log.info("Persisting adding assignable role update for user {} in server {} of role {}.", event.getMember().getIdLong(), guild.getIdLong(), roleById.getId());
self.persistAssignableUser(event.getMember(), payload, false);
});
}
});
} else {
roleService.removeRoleFromUserAsync(event.getMember(), roleById)
.thenAccept(unused -> {
self.notifyUser(model, false, roleById, event.getInteraction(), new ArrayList<>());
log.info("Removed role {} from member {} in server {} for assignable role interaction {} on component {}.",
roleById.getId(), event.getMember().getId(), guild.getIdLong(), event.getInteraction().getId(), event.getComponentId());
}).thenAccept(unused -> {
log.info("Persisting remove assignable role update for user {} in server {} of role {}.", event.getMember().getIdLong(), guild.getIdLong(), roleById.getId());
self.persistAssignableUser(event.getMember(), payload, true);
});
}
} else {
log.warn("Role {} is not available to be assigned in assignable role place {} in server {}. Component {} failed.",
payload.getRoleId(), payload.getPlaceId(), guild.getIdLong(), event.getComponentId());
throw new AssignableRoleNotFoundException(payload.getRoleId());
}
}
return ButtonClickedListenerResult.ACKNOWLEDGED;
}
@Transactional
public void persistAssignableUser(Member member, AssignableRolePlacePayload payload, boolean removeRole){
AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(payload.getPlaceId());
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
if(place.getUniqueRoles() && !removeRole) {
assignableRoleService.clearAllRolesOfUserInPlace(place, aUserInAServer);
}
Optional<AssignableRole> assignableRoleOptional = place
.getAssignableRoles()
.stream()
.filter(assignableRole -> assignableRole.getRole().getId().equals(payload.getRoleId()))
.findFirst();
if(assignableRoleOptional.isPresent()) {
if(removeRole) {
assignableRoleService.removeRoleFromUser(assignableRoleOptional.get(), aUserInAServer);
} else {
assignableRoleService.addRoleToUser(assignableRoleOptional.get(), aUserInAServer);
}
}
}
@Transactional
public CompletableFuture<Void> notifyUser(ButtonClickedListenerModel model, boolean roleAdded, Role role, ButtonInteraction buttonInteraction, List<Role> removedRoles) {
AssignableRoleSuccessNotificationModel notificationModel = AssignableRoleSuccessNotificationModel
.builder()
.added(roleAdded)
.removedRoles(removedRoles)
.role(role)
.build();
return FutureUtils.toSingleFutureGeneric(
interactionService.sendMessageToInteraction("assignable_role_success_notification", notificationModel, buttonInteraction.getHook())) ;
}
@Transactional
public CompletableFuture<Void> notifyUserAboutConditionFail(ButtonClickedListenerModel model, ButtonInteraction buttonInteraction,
AssignableRolePlaceConditionModel conditionModel) {
return FutureUtils.toSingleFutureGeneric(
interactionService.sendMessageToInteraction("assignable_role_condition_notification", conditionModel, buttonInteraction.getHook())) ;
}
@Override
public Boolean handlesEvent(ButtonClickedListenerModel model) {
return model.getOrigin().equals(AssignableRolePlaceServiceBean.ASSIGNABLE_ROLE_COMPONENT_ORIGIN);
}
@Override
public FeatureDefinition getFeature() {
return AssignableRoleFeatureDefinition.ASSIGNABLE_ROLES;
}
@Override
public Integer getPriority() {
return ListenerPriority.MEDIUM;
}
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.assignableroles.model;
import dev.sheldan.abstracto.core.models.template.button.ButtonPayload;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class AssignableRolePlacePayload implements ButtonPayload {
private Long placeId;
private Long roleId;
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.assignableroles.repository;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRoleCondition;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface AssignableRoleConditionRepository extends JpaRepository<AssignableRoleCondition, Long> {
Optional<AssignableRoleCondition> findByAssignableRoleAndType(AssignableRole assignableRole, AssignableRoleConditionType type);
}

View File

@@ -1,12 +0,0 @@
package dev.sheldan.abstracto.assignableroles.repository;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* Repository to manage the access to the table managed by {@link AssignableRolePlacePost posts}
*/
@Repository
public interface AssignableRolePlacePostRepository extends JpaRepository<AssignableRolePlacePost, Long> {
}

View File

@@ -0,0 +1,125 @@
package dev.sheldan.abstracto.assignableroles.service;
import dev.sheldan.abstracto.assignableroles.condition.AssignableRoleConditionEvaluator;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRoleConditionAlreadyExistsException;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRoleConditionValueNotUsableException;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionResult;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRoleCondition;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRoleConditionDoesNotExistException;
import dev.sheldan.abstracto.assignableroles.model.template.condition.AssignableRoleConditionDisplay;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRoleConditionManagementService;
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRolePlaceManagementService;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@Component
public class AssignableRoleConditionServiceBean implements AssignableRoleConditionService {
@Autowired
private List<AssignableRoleConditionEvaluator> assignableRoleConditionEvaluators;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private AssignableRolePlaceManagementService assignableRolePlaceManagementService;
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private AssignableRoleService assignableRoleService;
@Autowired
private AssignableRoleConditionManagementService assignableRoleConditionManagementService;
@Override
public AssignableRoleConditionResult evaluateConditions(List<AssignableRoleCondition> conditions, Member member, Role role) {
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
return evaluateConditions(conditions, aUserInAServer, role);
}
@Override
public AssignableRoleConditionResult evaluateConditions(List<AssignableRoleCondition> conditions, AUserInAServer aUserInAServer, Role role) {
for (AssignableRoleCondition condition : conditions) {
if(assignableRoleConditionEvaluators != null) {
Optional<AssignableRoleConditionEvaluator> evaluatorOptional = findEvaluatorForCondition(condition.getType());
if(evaluatorOptional.isPresent()) {
AssignableRoleConditionEvaluator evaluator = evaluatorOptional.get();
if(!evaluator.fulfillsCondition(condition, aUserInAServer)) {
return AssignableRoleConditionResult.fromFail(condition.getType(), evaluator.createNotificationModel(condition, role));
}
}
}
}
return AssignableRoleConditionResult.fromSuccess();
}
private Optional<AssignableRoleConditionEvaluator> findEvaluatorForCondition(AssignableRoleConditionType type) {
return assignableRoleConditionEvaluators
.stream()
.filter(assignableRoleConditionEvaluator -> assignableRoleConditionEvaluator.handlesCondition(type))
.findFirst();
}
@Override
public AssignableRoleCondition createAssignableRoleCondition(String placeName, Role role, AssignableRoleConditionType type, String value) {
AServer server = serverManagementService.loadServer(role.getGuild());
AssignableRolePlace place = assignableRolePlaceManagementService.findByServerAndKey(server, placeName);
AssignableRole assignableRole = assignableRoleService.getAssignableRoleInPlace(place, role);
Optional<AssignableRoleConditionEvaluator> evaluatorOptional = findEvaluatorForCondition(type);
if(!evaluatorOptional.isPresent()) {
throw new AssignableRoleConditionDoesNotExistException();
}
evaluatorOptional.ifPresent(evaluator -> {
boolean valueUsable = evaluator.usableValue(value);
if(!valueUsable) {
throw new AssignableRoleConditionValueNotUsableException();
}
});
if(assignableRoleConditionManagementService.findAssignableRoleCondition(assignableRole, type).isPresent()) {
throw new AssignableRoleConditionAlreadyExistsException();
}
return assignableRoleConditionManagementService.createAssignableRoleCondition(assignableRole, type, value);
}
@Override
public void deleteAssignableRoleCondition(String placeName, Role role, AssignableRoleConditionType type) {
AServer server = serverManagementService.loadServer(role.getGuild());
AssignableRolePlace place = assignableRolePlaceManagementService.findByServerAndKey(server, placeName);
AssignableRole assignableRole = assignableRoleService.getAssignableRoleInPlace(place, role);
Optional<AssignableRoleCondition> existingCondition = assignableRoleConditionManagementService.findAssignableRoleCondition(assignableRole, type);
if(!existingCondition.isPresent()) {
throw new AssignableRoleConditionDoesNotExistException();
}
existingCondition.ifPresent(condition -> assignableRoleConditionManagementService.deleteAssignableRoleCondition(condition));
}
@Override
public List<AssignableRoleConditionDisplay> getConditionDisplays(List<AssignableRoleCondition> conditions) {
return conditions.stream().map(condition -> {
Optional<AssignableRoleConditionEvaluator> evaluatorOptional = findEvaluatorForCondition(condition.getType());
if(evaluatorOptional.isPresent()) {
AssignableRoleConditionEvaluator evaluator = evaluatorOptional.get();
return evaluator.getConditionDisplay(condition);
}
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.assignableroles.service;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRoleNotFoundException;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
@@ -9,19 +10,21 @@ import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUser
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.ServerUser;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.MemberService;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Component
@@ -73,32 +76,27 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
metricService.incrementCounter(ASSIGNABLE_ROLES_ASSIGNED);
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
log.info("Assigning role {} to member {} in server {}.", assignableRoleId, member.getId(), member.getGuild().getId());
return roleService.addRoleToMemberFuture(member, role.getRole());
}
@Override
public CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, ServerUser serverUser) {
return memberService.retrieveMemberInServer(serverUser).thenCompose(member -> assignAssignableRoleToUser(assignableRoleId, member));
return roleService.addRoleToMemberAsync(member, role.getRole());
}
@Override
public void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer userInAServer) {
AssignedRoleUser user = assignedRoleUserManagementServiceBean.findByUserInServer(userInAServer);
log.info("Clearing all {} assignable roles in place {} for user {} in server {}.",
user.getRoles().size(), place.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
user.getRoles().forEach(assignableRole -> {
if(assignableRole.getAssignablePlace().equals(place)) {
assignableRole.getAssignedUsers().remove(user);
}
Optional<AssignedRoleUser> userOptional = assignedRoleUserManagementServiceBean.findByUserInServerOptional(userInAServer);
userOptional.ifPresent(assignedRoleUser -> {
log.info("Clearing all {} assignable roles in place {} for user {} in server {}.",
assignedRoleUser.getRoles().size(), place.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
assignedRoleUser.getRoles().forEach(assignableRole -> {
if(assignableRole.getAssignablePlace().equals(place)) {
assignableRole.getAssignedUsers().remove(assignedRoleUser);
}
});
assignedRoleUser.getRoles().removeIf(assignableRole -> assignableRole.getAssignablePlace().equals(place));
});
user.getRoles().removeIf(assignableRole -> assignableRole.getAssignablePlace().equals(place));
}
@Override
public CompletableFuture<Void> fullyAssignAssignableRoleToUser(Long assignableRoleId, Member toAdd) {
return this.assignAssignableRoleToUser(assignableRoleId, toAdd).thenAccept(aVoid ->
self.addRoleToUser(assignableRoleId, toAdd)
);
if(!userOptional.isPresent()) {
log.info("User {} was not yet stored as an assignable role user in server {} - nothing to clear.",
userInAServer.getUserReference().getId(), place.getServer().getId());
}
}
@Override
@@ -115,30 +113,6 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
return self.removeAssignableRoleFromUser(role, member);
}
@Override
public CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) {
Long assignableRoleId = assignableRole.getId();
return memberService.getMemberInServerAsync(aUserInAServer).thenCompose(member ->
self.removeAssignableRoleFromUser(assignableRoleId, member)
);
}
@Override
public CompletableFuture<Void> fullyRemoveAssignableRoleFromUser(AssignableRole assignableRole, ServerUser serverUser) {
Long assignableRoleId = assignableRole.getId();
return memberService.retrieveMemberInServer(serverUser).thenCompose(member ->
this.removeAssignableRoleFromUser(assignableRole, member)
.thenAccept(aVoid -> self.persistRoleRemovalFromUser(assignableRoleId, member))
);
}
@Transactional
@Override
public void addRoleToUser(Long assignableRoleId, AUserInAServer aUserInAServer) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
addRoleToUser(role, aUserInAServer);
}
@Override
public void addRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) {
log.info("Persisting storing adding assignable role {} to user {} in server {}.",
@@ -153,39 +127,24 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
assignedRoleUserManagementServiceBean.removeAssignedRoleFromUser(assignableRole, aUserInAServer);
}
/**
* Adds the given {@link AssignableRole assignableRole} identified by the ID to the given {@link Member member}
* @param assignableRoleId The ID of the {@link AssignableRole} to be added to the {@link Member member}
* @param member The {@link Member member} to add the {@link AssignableRole role} to
*/
@Transactional
public void addRoleToUser(Long assignableRoleId, Member member) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
addRoleToUser(role, aUserInAServer);
@Override
public AssignableRole getAssignableRoleInPlace(AssignableRolePlace place, Role role) {
return getAssignableRoleInPlace(place, role.getIdLong());
}
/**
* Removes the given {@link AssignableRole assignableRole} identified by the ID from the given {@link AUserInAServer user}
* @param assignableRoleId The ID of the {@link AssignableRole} to be removed from the {@link Member member}
* @param aUserInAServer The {@link AUserInAServer user} to remove the {@link AssignableRole role} from
*/
@Transactional
public void removeRoleFromUser(Long assignableRoleId, AUserInAServer aUserInAServer) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
removeRoleFromUser(role, aUserInAServer);
@Override
public AssignableRole getAssignableRoleInPlace(AssignableRolePlace place, ARole role) {
return getAssignableRoleInPlace(place, role.getId());
}
/**
* Stores the removal of an {@link AssignableRole assignableRole} from a {@link Member member} in the database
* @param assignableRoleId The ID of the {@link AssignableRole} to be removed from the {@link Member member}
* @param member The {@link Member member} which should get the {@link AssignableRole role} removed
*/
@Transactional
public void persistRoleRemovalFromUser(Long assignableRoleId, Member member) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
removeRoleFromUser(role, aUserInAServer);
@Override
public AssignableRole getAssignableRoleInPlace(AssignableRolePlace place, Long roleId) {
for (AssignableRole assignableRole : place.getAssignableRoles()) {
if (assignableRole.getRole().getId().equals(roleId)) {
return assignableRole;
}
}
throw new AssignableRoleNotFoundException(roleId);
}
@PostConstruct

View File

@@ -0,0 +1,39 @@
package dev.sheldan.abstracto.assignableroles.service.management;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRoleCondition;
import dev.sheldan.abstracto.assignableroles.repository.AssignableRoleConditionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
public class AssignableRoleConditionManagementServiceBean implements AssignableRoleConditionManagementService {
@Autowired
private AssignableRoleConditionRepository repository;
@Override
public AssignableRoleCondition createAssignableRoleCondition(AssignableRole assignableRole, AssignableRoleConditionType type, String value) {
AssignableRoleCondition condition = AssignableRoleCondition
.builder()
.assignableRole(assignableRole)
.type(type)
.conditionValue(value)
.build();
assignableRole.getConditions().add(condition);
return repository.save(condition);
}
@Override
public void deleteAssignableRoleCondition(AssignableRoleCondition condition) {
repository.delete(condition);
}
@Override
public Optional<AssignableRoleCondition> findAssignableRoleCondition(AssignableRole role, AssignableRoleConditionType type) {
return repository.findByAssignableRoleAndType(role, type);
}
}

View File

@@ -1,19 +1,17 @@
package dev.sheldan.abstracto.assignableroles.service.management;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRolePlaceNotFoundException;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.assignableroles.repository.AssignableRoleRepository;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.FullEmote;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.ComponentPayload;
import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.management.EmoteManagementService;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.entities.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -30,9 +28,6 @@ public class AssignableRoleManagementServiceBean implements AssignableRoleManage
@Autowired
private RoleManagementService roleManagementService;
@Autowired
private AssignableRolePlacePostManagementService postManagementService;
@Autowired
private AssignableRoleRepository repository;
@@ -40,45 +35,23 @@ public class AssignableRoleManagementServiceBean implements AssignableRoleManage
private EmoteService emoteService;
@Override
public AssignableRole addRoleToPlace(AssignableRolePlace place, AEmote emote, ARole role, String description, AssignableRolePlacePost post) {
Integer maxPosition = place.getAssignableRoles().stream().map(AssignableRole::getPosition).max(Integer::compareTo).orElse(0);
if(!place.getAssignableRoles().isEmpty()) {
maxPosition += 1;
}
public AssignableRole addRoleToPlace(FullEmote emote, Role role, String description, AssignableRolePlace place, ComponentPayload componentPayload) {
ARole arole = roleManagementService.findRole(role.getIdLong());
AssignableRole roleToAdd = AssignableRole
.builder()
.assignablePlace(place)
.emote(emote)
.role(role)
.requiredLevel(0)
.emoteMarkdown(emote != null ? emote.getEmoteRepr() : null)
.role(arole)
.componentPayload(componentPayload)
.server(place.getServer())
.position(maxPosition)
.description(description)
.assignableRolePlacePost(post)
.build();
place.getAssignableRoles().add(roleToAdd);
log.info("Adding role {} to assignable role place {}. There are now {} roles.", role.getId(), place.getId(), place.getAssignableRoles().size());
return roleToAdd;
}
@Override
public AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description, Long messageId) {
AssignableRolePlace place = rolePlaceManagementService.findByPlaceIdOptional(placeId).orElseThrow(() -> new AssignableRolePlaceNotFoundException(placeId));
AEmote emote = emoteManagementService.loadEmote(emoteId);
ARole role = roleManagementService.findRole(roleId);
AssignableRolePlacePost post = postManagementService.findByMessageId(messageId);
AssignableRole assignableRole = addRoleToPlace(place, emote, role, description, post);
post.getAssignableRoles().add(assignableRole);
return assignableRole;
}
@Override
public AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description) {
AssignableRolePlace place = rolePlaceManagementService.findByPlaceIdOptional(placeId).orElseThrow(() -> new AssignableRolePlaceNotFoundException(placeId));
AEmote emote = emoteManagementService.loadEmote(emoteId);
ARole role = roleManagementService.findRole(roleId);
return addRoleToPlace(place, emote, role, description, null);
}
@Override
public AssignableRole getByAssignableRoleId(Long assignableRoleId) {
@@ -86,26 +59,8 @@ public class AssignableRoleManagementServiceBean implements AssignableRoleManage
}
@Override
public AssignableRole getRoleForReactionEmote(CachedEmote cachedEmote, AssignableRolePlace assignableRolePlace) {
for (AssignableRolePlacePost post : assignableRolePlace.getMessagePosts()) {
for (AssignableRole assignableRole : post.getAssignableRoles()) {
if (emoteService.compareCachedEmoteWithAEmote(cachedEmote, assignableRole.getEmote())) {
return assignableRole;
}
}
}
throw new AbstractoRunTimeException("Role for reaction was not found.");
public void deleteAssignableRole(AssignableRole assignableRole) {
repository.delete(assignableRole);
}
@Override
public AssignableRole getRoleForReactionEmote(MessageReaction.ReactionEmote cachedEmote, AssignableRolePlace assignableRolePlace) {
for (AssignableRolePlacePost post : assignableRolePlace.getMessagePosts()) {
for (AssignableRole assignableRole : post.getAssignableRoles()) {
if (emoteService.isReactionEmoteAEmote(cachedEmote, assignableRole.getEmote())) {
return assignableRole;
}
}
}
throw new AbstractoRunTimeException("Role for reaction was not found.");
}
}

View File

@@ -39,8 +39,7 @@ public class AssignableRolePlaceManagementServiceBean implements AssignableRoleP
@Override
public AssignableRolePlace findByServerAndKey(AServer server, String name) {
// todo use other exception or adapt exception
return repository.findByServerAndKey(server, name).orElseThrow(() -> new AssignableRolePlaceNotFoundException(0L));
return repository.findByServerAndKey(server, name).orElseThrow(AssignableRolePlaceNotFoundException::new);
}
@Override
@@ -50,7 +49,7 @@ public class AssignableRolePlaceManagementServiceBean implements AssignableRoleP
@Override
public AssignableRolePlace findByPlaceId(Long id) {
return findByPlaceIdOptional(id).orElseThrow(() -> new AssignableRolePlaceNotFoundException(id));
return findByPlaceIdOptional(id).orElseThrow(AssignableRolePlaceNotFoundException::new);
}
@Override

View File

@@ -1,41 +0,0 @@
package dev.sheldan.abstracto.assignableroles.service.management;
import dev.sheldan.abstracto.assignableroles.exception.AssignableRolePlacePostNotFoundException;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.assignableroles.repository.AssignableRolePlacePostRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
public class AssignableRolePlacePostManagementServiceBean implements AssignableRolePlacePostManagementService {
@Autowired
private AssignableRolePlacePostRepository repository;
@Override
public Optional<AssignableRolePlacePost> findByMessageIdOptional(Long messageId) {
return repository.findById(messageId);
}
@Override
public AssignableRolePlacePost findByMessageId(Long messageId) {
return findByMessageIdOptional(messageId).orElseThrow(() -> new AssignableRolePlacePostNotFoundException(messageId));
}
@Override
public AssignableRolePlacePost createAssignableRolePlacePost(AssignableRolePlace updatedPlace, Long messageId) {
AssignableRolePlacePost post = AssignableRolePlacePost
.builder()
.id(messageId)
.usedChannel(updatedPlace.getChannel())
.server(updatedPlace.getServer())
.assignablePlace(updatedPlace)
.build();
updatedPlace.getMessagePosts().add(post);
return post;
}
}

View File

@@ -1,2 +1,2 @@
abstracto.featureFlags.emoteTracking.featureName=emoteTracking
abstracto.featureFlags.emoteTracking.enabled=false
abstracto.featureFlags.assignableRole.featureName=assignableRole
abstracto.featureFlags.assignableRole.enabled=false

View File

@@ -6,83 +6,78 @@
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="experienceModule" value="(SELECT id FROM module WHERE name = 'assignableRoles')"/>
<property name="experienceFeature" value="(SELECT id FROM feature WHERE key = 'assignableRole')"/>
<property name="assignableRoleModule" value="(SELECT id FROM module WHERE name = 'assignableRoles')"/>
<property name="assignableRoleFeature" value="(SELECT id FROM feature WHERE key = 'assignableRole')"/>
<changeSet author="Sheldan" id="assignable_roles-commands">
<insert tableName="command">
<column name="name" value="addRoleToAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="setupAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="activateAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="deactivateAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="removeRoleFromAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="changeAssignableRolePlaceConfig"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="setAssignableRolePosition"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="swapAssignableRolePosition"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="testAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="deleteAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="createAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="showAssignableRolePlaceConfig"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="editAssignableRolePlaceText"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="moveAssignableRolePlace"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="showAssignableRolePlaces"/>
<column name="module_id" valueComputed="${experienceModule}"/>
<column name="feature_id" valueComputed="${experienceFeature}"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="addAssignableRoleCondition"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="removeAssignableRoleCondition"/>
<column name="module_id" valueComputed="${assignableRoleModule}"/>
<column name="feature_id" valueComputed="${assignableRoleFeature}"/>
</insert>
</changeSet>

View File

@@ -11,8 +11,8 @@
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="assignable_role_pkey"/>
</column>
<column name="emote_id" type="INTEGER">
<constraints nullable="false"/>
<column name="emote_markdown" type="VARCHAR(100)">
<constraints nullable="true"/>
</column>
<column name="role_id" type="BIGINT">
<constraints nullable="false"/>
@@ -23,26 +23,22 @@
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="place_post_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="description" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="required_level" type="INTEGER"/>
<column name="position" type="INTEGER">
<constraints nullable="false"/>
</column>
<column name="component_id" type="VARCHAR(100)" />
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>
<addForeignKeyConstraint baseColumnNames="emote_id" baseTableName="assignable_role" constraintName="fk_assignable_role_emote" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="emote" validate="true"/>
<createIndex indexName="idx_assignable_role_role_id" tableName="assignable_role">
<column name="role_id"/>
</createIndex>
<addForeignKeyConstraint baseColumnNames="role_id" baseTableName="assignable_role" constraintName="fk_assignable_role_role" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="role" validate="true"/>
<addForeignKeyConstraint baseColumnNames="assignable_place_id" baseTableName="assignable_role" constraintName="fk_assignable_role_place" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="assignable_role_place" validate="true"/>
<addForeignKeyConstraint baseColumnNames="place_post_id" baseTableName="assignable_role" constraintName="fk_assignable_role_post" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="assignable_role_place_post" validate="true"/>
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="assignable_role" constraintName="fk_assignable_role_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
<addForeignKeyConstraint baseColumnNames="component_id" baseTableName="assignable_role" constraintName="fk_assignable_role_payload" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="component_payload" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS assignable_role_update_trigger ON assignable_role;
CREATE TRIGGER assignable_role_update_trigger BEFORE UPDATE ON assignable_role FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();

View File

@@ -0,0 +1,33 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="assignable_role_condition-table">
<createTable tableName="assignable_role_condition">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="assignable_role_condition_pkey"/>
</column>
<column name="type" type="VARCHAR(100)">
<constraints nullable="false"/>
</column>
<column name="assignable_role_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="condition_value" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>
<addForeignKeyConstraint baseColumnNames="assignable_role_id" baseTableName="assignable_role_condition" constraintName="fk_assignable_role_condition_assignable_role"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="assignable_role" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS assignable_role_condition_insert_trigger ON assignable_role_condition;
CREATE TRIGGER assignable_role_condition_insert_trigger BEFORE INSERT ON assignable_role_condition FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -23,18 +23,10 @@
<column name="text" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="active" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="inline" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="unique_roles" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="auto_remove" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="message_id" type="BIGINT" />
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>

View File

@@ -1,41 +0,0 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<changeSet author="Sheldan" id="assignable_role_place_post-table">
<createTable tableName="assignable_role_place_post">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true" primaryKeyName="assignable_role_place_post_pkey"/>
</column>
<column name="assignable_place_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="channel_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="server_id" type="BIGINT">
<constraints nullable="false"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>
<addForeignKeyConstraint baseColumnNames="assignable_place_id" baseTableName="assignable_role_place_post" constraintName="fk_assignable_role_place_post_place_id" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="assignable_role_place" validate="true"/>
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="assignable_role_place_post" constraintName="fk_assignable_role_place_post_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
<addForeignKeyConstraint baseColumnNames="channel_id" baseTableName="assignable_role_place_post" constraintName="fk_assignable_role_place_post_channel" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="channel" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS assignable_role_place_post_update_trigger ON assignable_role_place_post;
CREATE TRIGGER assignable_role_place_post_update_trigger BEFORE UPDATE ON assignable_role_place_post FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS assignable_role_place_post_insert_trigger ON assignable_role_place_post;
CREATE TRIGGER assignable_role_place_post_insert_trigger BEFORE INSERT ON assignable_role_place_post FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -7,7 +7,7 @@
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="assignable_role_place.xml" relativeToChangelogFile="true"/>
<include file="assignable_role_place_post.xml" relativeToChangelogFile="true"/>
<include file="assignable_role.xml" relativeToChangelogFile="true"/>
<include file="assignable_role_condition.xml" relativeToChangelogFile="true"/>
<include file="assigned_role_user.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

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

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.assignableroles.condition;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRolePlaceConditionModel;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRoleCondition;
import dev.sheldan.abstracto.assignableroles.model.template.condition.AssignableRoleConditionDisplay;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import net.dv8tion.jda.api.entities.Role;
public interface AssignableRoleConditionEvaluator {
boolean handlesCondition(AssignableRoleConditionType type);
boolean fulfillsCondition(AssignableRoleCondition conditionDefinition, AUserInAServer aUserInAServer);
boolean usableValue(String value);
AssignableRolePlaceConditionModel createNotificationModel(AssignableRoleCondition conditionDefinition, Role role);
AssignableRoleConditionDisplay getConditionDisplay(AssignableRoleCondition conditionDefinition);
}

View File

@@ -3,11 +3,7 @@ package dev.sheldan.abstracto.assignableroles.config;
import dev.sheldan.abstracto.core.command.execution.CommandParameterKey;
import lombok.Getter;
/**
* This enum is used to define the different key for which there exist properties on an {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace}.
* And is used for the command parameter when changing the value of an attribute on this place.
*/
@Getter
public enum AssignableRolePlaceParameterKey implements CommandParameterKey {
INLINE, UNIQUE, AUTOREMOVE, ACTIVE
UNIQUE
}

View File

@@ -2,8 +2,9 @@ package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.assignableroles.model.exception.AssignableRoleAlreadyDefinedExceptionModel;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.FullEmote;
import dev.sheldan.abstracto.core.models.template.display.RoleDisplay;
import dev.sheldan.abstracto.core.templating.Templatable;
import net.dv8tion.jda.api.entities.Role;
/**
* Exception thrown in case the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole} has already been
@@ -13,14 +14,18 @@ import dev.sheldan.abstracto.core.templating.Templatable;
public class AssignableRoleAlreadyDefinedException extends AbstractoRunTimeException implements Templatable {
private final AssignableRoleAlreadyDefinedExceptionModel model;
public AssignableRoleAlreadyDefinedException(FullEmote emote, String placeName) {
public AssignableRoleAlreadyDefinedException(Role role, String placeName) {
super("Assignable role already assigned");
this.model = AssignableRoleAlreadyDefinedExceptionModel.builder().emote(emote).placeName(placeName).build();
this.model = AssignableRoleAlreadyDefinedExceptionModel
.builder()
.roleDisplay(RoleDisplay.fromRole(role))
.placeName(placeName)
.build();
}
@Override
public String getTemplateName() {
return "assignable_role_place_emote_already_defined_exception";
return "assignable_role_already_defined_exception";
}
@Override

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class AssignableRoleConditionAlreadyExistsException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "assignable_role_condition_already_present_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class AssignableRoleConditionDoesNotExistException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "assignable_role_condition_does_not_exist_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class AssignableRoleConditionValueNotUsableException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "assignable_role_condition_value_not_usable_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,27 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.assignableroles.model.exception.AssignableRoleNotFoundExceptionModel;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class AssignableRoleNotFoundException extends AbstractoTemplatableException {
private final AssignableRoleNotFoundExceptionModel model;
public AssignableRoleNotFoundException(Long roleId) {
super("Role to assign is not available anymore.");
this.model = AssignableRoleNotFoundExceptionModel
.builder()
.roleId(roleId)
.build();
}
@Override
public String getTemplateName() {
return "assignable_role_not_found_exception";
}
@Override
public Object getTemplateModel() {
return this.model;
}
}

View File

@@ -2,9 +2,9 @@ package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.assignableroles.model.exception.AssignableRoleNotUsableExceptionModel;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.FullRole;
import dev.sheldan.abstracto.core.models.template.display.RoleDisplay;
import dev.sheldan.abstracto.core.templating.Templatable;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Role;
/**
* Exception thrown in case the defined {@link net.dv8tion.jda.api.entities.Role role} cannot be interacted with by the bot,
@@ -14,14 +14,17 @@ import net.dv8tion.jda.api.entities.Guild;
public class AssignableRoleNotUsableException extends AbstractoRunTimeException implements Templatable {
private final AssignableRoleNotUsableExceptionModel model;
public AssignableRoleNotUsableException(FullRole role, Guild guild) {
public AssignableRoleNotUsableException(Role role) {
super("Role is not usable as assignable role");
this.model = AssignableRoleNotUsableExceptionModel.builder().role(role).guild(guild).build();
this.model = AssignableRoleNotUsableExceptionModel
.builder()
.roleDisplay(RoleDisplay.fromRole(role))
.build();
}
@Override
public String getTemplateName() {
return "assignable_role_place_role_not_usable_exception";
return "assignable_role_not_usable_exception";
}
@Override

View File

@@ -14,7 +14,10 @@ public class AssignableRolePlaceAlreadyExistsException extends AbstractoRunTimeE
public AssignableRolePlaceAlreadyExistsException(String name) {
super("Assignable role place already exists");
this.model = AssignableRolePlaceAlreadyExistsExceptionModel.builder().name(name).build();
this.model = AssignableRolePlaceAlreadyExistsExceptionModel
.builder()
.name(name)
.build();
}
@Override

View File

@@ -14,7 +14,11 @@ public class AssignableRolePlaceChannelDoesNotExistException extends AbstractoRu
public AssignableRolePlaceChannelDoesNotExistException(Long channelId, String placeName) {
super("Assignable role place channel does not exist");
this.model = AssignableRolePlaceChannelDoesNotExistExceptionModel.builder().channelId(channelId).placeName(placeName).build();
this.model = AssignableRolePlaceChannelDoesNotExistExceptionModel
.builder()
.channelId(channelId)
.placeName(placeName)
.build();
}
@Override

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class AssignableRolePlaceIllegalConfigurationException extends AbstractoTemplatableException {
public AssignableRolePlaceIllegalConfigurationException() {
super("An illegal configuration key has been passed to configure the assignable role place config. Doing nothing.");
}
@Override
public String getTemplateName() {
return "assignable_role_place_illegal_configuration_key_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,20 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class AssignableRolePlaceMaximumRolesException extends AbstractoTemplatableException {
public AssignableRolePlaceMaximumRolesException() {
super("The maximum amount of assignable roles have been reached.");
}
@Override
public String getTemplateName() {
return "assignable_role_place_maximum_roles_reached_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -1,20 +1,12 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.assignableroles.model.exception.AssignableRolePlaceNotFoundExceptionModel;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
/**
* Exception which is thrown in case a {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
* defined by a {@link String key} does not exist
*/
public class AssignableRolePlaceNotFoundException extends AbstractoRunTimeException implements Templatable {
private final AssignableRolePlaceNotFoundExceptionModel model;
public AssignableRolePlaceNotFoundException(Long placeId) {
public AssignableRolePlaceNotFoundException() {
super("Assignable role place not found");
this.model = AssignableRolePlaceNotFoundExceptionModel.builder().placeId(placeId).build();
}
@Override
@@ -24,6 +16,6 @@ public class AssignableRolePlaceNotFoundException extends AbstractoRunTimeExcept
@Override
public Object getTemplateModel() {
return model;
return new Object();
}
}

View File

@@ -1,29 +0,0 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.assignableroles.model.exception.AssignableRolePlacePostNotFoundExceptionModel;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
/**
* Exception which is thrown, in case the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost post}
* was not found via its message ID
*/
public class AssignableRolePlacePostNotFoundException extends AbstractoRunTimeException implements Templatable {
private final AssignableRolePlacePostNotFoundExceptionModel model;
public AssignableRolePlacePostNotFoundException(Long messageId) {
super("Assignable place post not found.");
this.model = AssignableRolePlacePostNotFoundExceptionModel.builder().messageId(messageId).build();
}
@Override
public String getTemplateName() {
return "assignable_role_place_post_not_found_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -15,7 +15,10 @@ public class AssignedUserNotFoundException extends AbstractoRunTimeException imp
public AssignedUserNotFoundException(AUserInAServer userInAServer) {
super("Assigned user was not found");
this.model = AssignedUserNotFoundExceptionModel.builder().aUserInAServer(userInAServer).build();
this.model = AssignedUserNotFoundExceptionModel
.builder()
.userId(userInAServer.getUserReference().getId())
.build();
}
@Override

View File

@@ -1,31 +0,0 @@
package dev.sheldan.abstracto.assignableroles.exception;
import dev.sheldan.abstracto.assignableroles.model.exception.EmoteNotInAssignableRolePlaceExceptionModel;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.FullEmote;
import dev.sheldan.abstracto.core.templating.Templatable;
/**
* Exception which is thrown in case a given {@link dev.sheldan.abstracto.core.models.database.AEmote} was not found
* in the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace}, when it was tried to switch
* or move the emotes around.
*/
public class EmoteNotInAssignableRolePlaceException extends AbstractoRunTimeException implements Templatable {
private final EmoteNotInAssignableRolePlaceExceptionModel model;
public EmoteNotInAssignableRolePlaceException(FullEmote emote, String placeName) {
super("Emote not found in assignable role place");
this.model = EmoteNotInAssignableRolePlaceExceptionModel.builder().emote(emote).placeName(placeName).build();
}
@Override
public String getTemplateName() {
return "emote_not_in_assignable_role_place_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -0,0 +1,38 @@
package dev.sheldan.abstracto.assignableroles.model.condition;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class AssignableRoleConditionResult {
private Boolean fulfilled;
private AssignableRoleConditionType causingCondition;
private AssignableRolePlaceConditionModel model;
public static AssignableRoleConditionResult fromFail(AssignableRoleConditionType cause, AssignableRolePlaceConditionModel model) {
return AssignableRoleConditionResult
.builder()
.causingCondition(cause)
.model(model)
.fulfilled(false)
.build();
}
public static AssignableRoleConditionResult fromFail(AssignableRoleConditionType cause) {
return AssignableRoleConditionResult
.builder()
.causingCondition(cause)
.fulfilled(false)
.build();
}
public static AssignableRoleConditionResult fromSuccess() {
return AssignableRoleConditionResult
.builder()
.fulfilled(true)
.build();
}
}

View File

@@ -0,0 +1,7 @@
package dev.sheldan.abstracto.assignableroles.model.condition;
import dev.sheldan.abstracto.core.command.execution.CommandParameterKey;
public enum AssignableRoleConditionType implements CommandParameterKey {
MIN_LEVEL
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.assignableroles.model.condition;
import dev.sheldan.abstracto.core.models.template.display.RoleDisplay;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class AssignableRoleMinLevelModel {
private Integer minLevel;
private RoleDisplay roleDisplay;
}

View File

@@ -0,0 +1,22 @@
package dev.sheldan.abstracto.assignableroles.model.condition;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class AssignableRoleMinLevelResult implements AssignableRolePlaceConditionModel {
private AssignableRoleMinLevelModel model;
@Override
public String getTemplateName() {
return "assignable_role_condition_min_level";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.assignableroles.model.condition;
import dev.sheldan.abstracto.core.templating.Templatable;
public interface AssignableRolePlaceConditionModel extends Templatable {
}

View File

@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.assignableroles.model.database;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.ComponentPayload;
import lombok.*;
import javax.persistence.*;
@@ -33,12 +34,8 @@ public class AssignableRole implements Serializable {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* The {@link AEmote emote} this role is associated with
*/
@OneToOne(fetch = FetchType.LAZY, orphanRemoval = true)
@JoinColumn(name = "emote_id", nullable = false)
private AEmote emote;
@Column(name = "emote_markdown")
private String emoteMarkdown;
/**
* The {@link ARole} which given via this {@link AssignableRole assignableRole}
@@ -61,14 +58,6 @@ public class AssignableRole implements Serializable {
@JoinColumn(name = "assignable_place_id", nullable = false)
private AssignableRolePlace assignablePlace;
/**
* The {@link AssignableRolePlacePost} this assignable role is currently available as a reaction.
* This is necessary, to easier find the reaction which are valid, in case a reaction is added to a post
*/
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "place_post_id")
private AssignableRolePlacePost assignableRolePlacePost;
/**
* The {@link AssignedRoleUser users} which currently have this role assigned via this mechanism.
* This is necessary to enforce the unique property of {@link AssignableRolePlace}, in which you only may chose one
@@ -79,23 +68,14 @@ public class AssignableRole implements Serializable {
private List<AssignedRoleUser> assignedUsers = new ArrayList<>();
/**
* The description which is shown in the embeds of the posts of the {@link AssignableRolePlace}
* The display text which is used for the button
*/
@Column(name = "description", nullable = false)
private String description;
/**
* The level in experience which is required in order to receive this {@link AssignableRole}
*/
@Column(name = "required_level")
private Integer requiredLevel;
/**
* The position of this assignable role within the {@link AssignableRole}. This is required in order to show them
* the same order as the descriptions in the fields and also to move them around and switch positions
*/
@Column(name = "position", nullable = false)
private Integer position;
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "component_id", nullable = false)
private ComponentPayload componentPayload;
/**
* The {@link Instant} this entity was created
@@ -108,4 +88,13 @@ public class AssignableRole implements Serializable {
*/
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
orphanRemoval = true,
mappedBy = "assignableRole"
)
@Builder.Default
private List<AssignableRoleCondition> conditions = new ArrayList<>();
}

View File

@@ -0,0 +1,34 @@
package dev.sheldan.abstracto.assignableroles.model.database;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import lombok.*;
import javax.persistence.*;
@Entity
@Table(name = "assignable_role_condition")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
public class AssignableRoleCondition {
@Id
@Column(name = "id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Getter
@Enumerated(EnumType.STRING)
@Column(name = "type")
private AssignableRoleConditionType type;
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "assignable_role_id", nullable = false)
private AssignableRole assignableRole;
@Column(name = "condition_value")
private String conditionValue;
}

View File

@@ -10,11 +10,6 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
/**
* The place entity holding the {@link AssignableRole roles} and {@link AssignableRolePlacePost posts} together.
* This is also the entity holding all the configuration for the place and is identified by a key as a String, which is unique
* for each server. This place holds the {@link AChannel} in which the
*/
@Entity
@Table(name = "assignable_role_place")
@Builder
@@ -36,9 +31,6 @@ public class AssignableRolePlace implements Serializable {
@Column(name = "id", nullable = false)
private Long id;
/**
* The channel in which the {@link AssignableRolePlacePost posts} for this place should be created
*/
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="channel_id", nullable = false)
private AChannel channel;
@@ -56,19 +48,6 @@ public class AssignableRolePlace implements Serializable {
@Column(name = "key", nullable = false)
private String key;
/**
* The {@link AssignableRolePlacePost posts} which were created when this place was setup. Is empty in the beginning
* and actively maintained in case a post is deleted.
*/
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
orphanRemoval = true,
mappedBy = "assignablePlace"
)
@Builder.Default
private List<AssignableRolePlacePost> messagePosts = new ArrayList<>();
/**
* A List containing the {@link AssignableRole} which are associated with this place
*/
@@ -81,26 +60,12 @@ public class AssignableRolePlace implements Serializable {
@Builder.Default
private List<AssignableRole> assignableRoles = new ArrayList<>();
/**
* The text which is displayed in the first description area of the created {@link AssignableRolePlacePost}
*/
@Column(name = "message_id")
private Long messageId;
@Column(name = "text", nullable = false)
private String text;
/**
* Whether or not the reactions placed onto the posts should be acted upon
*/
@Builder.Default
@Column(name = "active", nullable = false)
private Boolean active = true;
/**
* Whether or not the fields containing the descriptions should be inline
*/
@Builder.Default
@Column(name = "inline", nullable = false)
private Boolean inline = false;
/**
* Whether or not it should be restricted, that a {@link AssignedRoleUser} should only have one role of this place
*/
@@ -108,13 +73,6 @@ public class AssignableRolePlace implements Serializable {
@Column(name = "unique_roles", nullable = false)
private Boolean uniqueRoles = false;
/**
* Whether or not the added reactions should be removed automatically
*/
@Builder.Default
@Column(name = "auto_remove", nullable = false)
private Boolean autoRemove = false;
/**
* The {@link Instant} this entity was created
*/

View File

@@ -1,78 +0,0 @@
package dev.sheldan.abstracto.assignableroles.model.database;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import lombok.*;
import javax.persistence.*;
import java.io.Serializable;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
/**
* One individual {@link net.dv8tion.jda.api.entities.Message message} which was sent when setting up an {@link AssignableRolePlace place}
* and contains the embeds and the reactions were placed onto it.
*/
@Entity
@Table(name = "assignable_role_place_post")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
public class AssignableRolePlacePost implements Serializable {
/**
* The ID of the {@link net.dv8tion.jda.api.entities.Message message} which represents this post with the reactions.
*/
@Id
@Column(name = "id", nullable = false)
private Long id;
/**
* The actual {@link AChannel channel} in which the post ended up in
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "channel_id", nullable = false)
private AChannel usedChannel;
/**
* The {@link AServer server} in which this place post is posted
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "server_id", nullable = false)
private AServer server;
/**
* The {@link AssignableRolePlace place} this post is associated with
*/
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "assignable_place_id", nullable = false)
private AssignableRolePlace assignablePlace;
/**
* The actual {@link AssignableRole assignableRoles} which are associated with this post, and whose respective {@link dev.sheldan.abstracto.core.models.database.AEmote}
* have been placed as reactions
*/
@OneToMany(
fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
mappedBy = "assignableRolePlacePost")
@Builder.Default
private List<AssignableRole> assignableRoles = new ArrayList<>();
/**
* The {@link Instant} this entity was created
*/
@Column(name = "created", nullable = false, insertable = false, updatable = false)
private Instant created;
/**
* The {@link Instant} this entity was updated
*/
@Column(name = "updated", insertable = false, updatable = false)
private Instant updated;
}

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.assignableroles.model.exception;
import dev.sheldan.abstracto.core.models.FullEmote;
import dev.sheldan.abstracto.core.models.template.display.RoleDisplay;
import lombok.Builder;
import lombok.Getter;
@@ -12,13 +12,6 @@ import java.io.Serializable;
@Getter
@Builder
public class AssignableRoleAlreadyDefinedExceptionModel implements Serializable {
/**
* The {@link FullEmote emote} which was tried to be added to a {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
*/
private final FullEmote emote;
/**
* The key of the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace} for which it was tried to add a
* {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole role}
*/
private final RoleDisplay roleDisplay;
private final String placeName;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.assignableroles.model.exception;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@Builder
public class AssignableRoleNotFoundExceptionModel implements Serializable {
private Long roleId;
private String displayText;
}

View File

@@ -1,9 +1,8 @@
package dev.sheldan.abstracto.assignableroles.model.exception;
import dev.sheldan.abstracto.core.models.FullRole;
import dev.sheldan.abstracto.core.models.template.display.RoleDisplay;
import lombok.Builder;
import lombok.Getter;
import net.dv8tion.jda.api.entities.Guild;
import java.io.Serializable;
@@ -13,12 +12,5 @@ import java.io.Serializable;
@Getter
@Builder
public class AssignableRoleNotUsableExceptionModel implements Serializable {
/**
* The {@link FullRole role} which is not usable as an {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole role}
*/
private final FullRole role;
/**
* The {@link Guild server} in which it was not possible to use the {@link net.dv8tion.jda.api.entities.Role role}
*/
private final transient Guild guild;
private final RoleDisplay roleDisplay;
}

View File

@@ -1,18 +0,0 @@
package dev.sheldan.abstracto.assignableroles.model.exception;
import lombok.Builder;
import lombok.Getter;
import java.io.Serializable;
/**
* Contains the model for {@link dev.sheldan.abstracto.assignableroles.exception.AssignableRolePlaceNotFoundException}
*/
@Getter
@Builder
public class AssignableRolePlaceNotFoundExceptionModel implements Serializable {
/**
* The ID of the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place} which was not found
*/
private final Long placeId;
}

View File

@@ -1,18 +0,0 @@
package dev.sheldan.abstracto.assignableroles.model.exception;
import lombok.Builder;
import lombok.Getter;
import java.io.Serializable;
/**
* Contains the model for {@link dev.sheldan.abstracto.assignableroles.exception.AssignableRolePlacePostNotFoundException}
*/
@Getter
@Builder
public class AssignableRolePlacePostNotFoundExceptionModel implements Serializable {
/**
* The ID of the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost post} which was not found in the database
*/
private final Long messageId;
}

View File

@@ -1,6 +1,5 @@
package dev.sheldan.abstracto.assignableroles.model.exception;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import lombok.Builder;
import lombok.Getter;
@@ -12,8 +11,5 @@ import java.io.Serializable;
@Getter
@Builder
public class AssignedUserNotFoundExceptionModel implements Serializable {
/**
* The instance of the {@link AUserInAServer userInAServer} for which the assigned user was not found
*/
private final AUserInAServer aUserInAServer;
private final Long userId;
}

View File

@@ -1,23 +0,0 @@
package dev.sheldan.abstracto.assignableroles.model.exception;
import dev.sheldan.abstracto.core.models.FullEmote;
import lombok.Builder;
import lombok.Getter;
import java.io.Serializable;
/**
* Contains the model for {@link dev.sheldan.abstracto.assignableroles.exception.EmoteNotInAssignableRolePlaceException}
*/
@Getter
@Builder
public class EmoteNotInAssignableRolePlaceExceptionModel implements Serializable {
/**
* The {@link FullEmote emote} which was not found in the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
*/
private final FullEmote emote;
/**
* The key of the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place} for which the emote was not found in
*/
private final String placeName;
}

View File

@@ -19,5 +19,5 @@ public class AssignablePlaceOverview {
* The {@link AssignableRolePlace places} in the server to display
*/
@Builder.Default
private List<AssignableRolePlace> places = new ArrayList<>();
private List<AssignableRolePlaceConfig> places = new ArrayList<>();
}

View File

@@ -5,7 +5,9 @@ import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Model used to render the {@link AssignableRolePlace place}
@@ -14,10 +16,8 @@ import java.util.List;
@Setter
@Builder
public class AssignablePostMessage {
/**
* The {@link AssignableRolePlace place} to render
*/
private AssignableRolePlace place;
private Long placeId;
private String placeDescription;
/**
* The awarded {@link AssignablePostRole roles} for this {@link AssignableRolePlace place}
*/
@@ -27,4 +27,6 @@ public class AssignablePostMessage {
* {@link AssignableRolePlace place}
*/
private Integer maxPosition;
@Builder.Default
private Map<String, Long> componentIdToRole = new HashMap<>();
}

View File

@@ -1,40 +1,14 @@
package dev.sheldan.abstracto.assignableroles.model.template;
import dev.sheldan.abstracto.core.models.FullEmote;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
/**
* The model which is used to render the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost post}
* to a {@link dev.sheldan.abstracto.core.templating.model.MessageToSend messageToSend} for one individual {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole role}
*/
@Getter
@Setter
@Builder
public class AssignablePostRole {
/**
* The {@link FullEmote emote} to be used in the field
*/
private FullEmote emote;
/**
* The description to be used in the field
*/
private String emoteMarkDown;
private String description;
/**
* The relative position within the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place} of this
* {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole role}
*/
private Integer position;
/**
* Whether or not this field should be at the beginning of a new {@link net.dv8tion.jda.api.entities.Message message}
* to be send
*/
@Builder.Default
private Boolean forceNewMessage = false;
/**
* Whether or not the field should be displayed inline
*/
private Boolean inline;
private String componentId;
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.assignableroles.model.template;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.core.models.template.display.ChannelDisplay;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@@ -14,10 +15,10 @@ import java.util.List;
@Setter
@Builder
public class AssignableRolePlaceConfig {
/**
* The {@link AssignableRolePlace place} to show the config of
*/
private AssignableRolePlace place;
private String placeName;
private String placeText;
private ChannelDisplay channelDisplay;
private Boolean uniqueRoles;
/**
* The {@link AssignableRolePlaceConfig roles} which are contained in this {@link AssignableRolePlace}
*/

View File

@@ -1,11 +1,13 @@
package dev.sheldan.abstracto.assignableroles.model.template;
import dev.sheldan.abstracto.core.models.FullEmote;
import dev.sheldan.abstracto.assignableroles.model.template.condition.AssignableRoleConditionDisplay;
import dev.sheldan.abstracto.core.models.template.display.RoleDisplay;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Role;
import java.util.List;
/**
* Model used to display the configuration of an individual {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole}
@@ -15,24 +17,8 @@ import net.dv8tion.jda.api.entities.Role;
@Setter
@Builder
public class AssignableRolePlaceConfigRole {
/**
* The description used for the field for this {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole role}
*/
private String description;
/**
* The position of this {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole role}
*/
private Integer position;
/**
* Whether or not the field is displayed inline
*/
private Boolean inline;
/**
* The {@link FullEmote emote} which is associated with this {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole role}
*/
private FullEmote emote;
/**
* The {@link dev.sheldan.abstracto.core.models.database.ARole} which is given/removed upon reacting with the emote
*/
private Role awardedRole;
private String emoteMarkDown;
private RoleDisplay roleDisplay;
private List<AssignableRoleConditionDisplay> conditions;
}

View File

@@ -0,0 +1,17 @@
package dev.sheldan.abstracto.assignableroles.model.template;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Role;
import java.util.List;
@Getter
@Setter
@Builder
public class AssignableRoleSuccessNotificationModel {
private Role role;
private Boolean added;
private List<Role> removedRoles;
}

View File

@@ -0,0 +1,8 @@
package dev.sheldan.abstracto.assignableroles.model.template.condition;
import dev.sheldan.abstracto.core.templating.Templatable;
public interface AssignableRoleConditionDisplay extends Templatable {
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.assignableroles.model.template.condition;
public class AssignableRoleMinLevelDisplay implements AssignableRoleConditionDisplay {
private final AssignableRoleMinLevelDisplayModel model;
public AssignableRoleMinLevelDisplay(Integer level) {
this.model = AssignableRoleMinLevelDisplayModel
.builder()
.minLevel(level)
.build();
}
@Override
public String getTemplateName() {
return "assignable_role_condition_display_min_level";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -0,0 +1,12 @@
package dev.sheldan.abstracto.assignableroles.model.template.condition;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class AssignableRoleMinLevelDisplayModel {
private Integer minLevel;
}

View File

@@ -0,0 +1,19 @@
package dev.sheldan.abstracto.assignableroles.service;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionResult;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRoleCondition;
import dev.sheldan.abstracto.assignableroles.model.template.condition.AssignableRoleConditionDisplay;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import java.util.List;
public interface AssignableRoleConditionService {
AssignableRoleConditionResult evaluateConditions(List<AssignableRoleCondition> conditions, Member member, Role role);
AssignableRoleConditionResult evaluateConditions(List<AssignableRoleCondition> conditions, AUserInAServer aUserInAServer, Role role);
AssignableRoleCondition createAssignableRoleCondition(String placeName, Role role, AssignableRoleConditionType type, String value);
void deleteAssignableRoleCondition(String placeName, Role role, AssignableRoleConditionType type);
List<AssignableRoleConditionDisplay> getConditionDisplays(List<AssignableRoleCondition> conditions);
}

View File

@@ -1,431 +1,56 @@
package dev.sheldan.abstracto.assignableroles.service;
import dev.sheldan.abstracto.assignableroles.config.AssignableRolePlaceParameterKey;
import dev.sheldan.abstracto.assignableroles.exception.EmoteNotInAssignableRolePlaceException;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException;
import dev.sheldan.abstracto.core.exception.ChannelNotInGuildException;
import dev.sheldan.abstracto.core.models.FullEmote;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.TextChannel;
import java.util.concurrent.CompletableFuture;
/**
* Service responsible to manage actions on an {@link AssignableRolePlace assignableRolePlace}
*/
public interface AssignableRolePlaceService {
/**
* Creates a {@link AssignableRolePlace place} with the given parameters
* @param name The key of the {@link AssignableRolePlace} to be used
* @param channel The {@link AChannel channel} in which the posts of this {@link AssignableRolePlace place} should be posted, also determines
* the {@link AServer server} in which the place should reside in. This {@link AServer server} needs to be unique in combination with the
* key
* @param text The description of the {@link AssignableRolePlace place} which is displayed in the first post of the place
* @throws dev.sheldan.abstracto.assignableroles.exception.AssignableRoleAlreadyDefinedException if the combination of {@link AServer server}
* and {@link AssignableRolePlace#key} already exists
*/
void createAssignableRolePlace(String name, AChannel channel, String text);
/**
* Whether or not the {@link AssignableRolePlace place} already has the given {@link AEmote emote} as an {@link AssignableRole role}
* with the given {@link AEmote emote}
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} should be in
* @param placeName The key of an {@link AssignableRolePlace place} to check
* @param emote The {@link AEmote emote} which is sought after
* @return Whether or not the {@link AssignableRolePlace place} already has an {@link AssignableRole role}
* with the associated {@link AEmote emote}
*/
boolean hasAssignableRolePlaceEmote(AServer server, String placeName, AEmote emote);
CompletableFuture<Void> addRoleToAssignableRolePlace(AServer server, String placeName, Role role, FullEmote emote, String description);
/**
* Whether or not the {@link AssignableRolePlace place} (identified by {@link AServer server} and placeName) already has
* the given {@link AEmote emote} as an {@link AssignableRole role}
* with the given {@link AEmote emote}
* @param place The {@link AssignableRolePlace place} in which the {@link AEmote emote} should be sought in
* @param emote The {@link AEmote emote} which is sought after
* @return Whether or not the {@link AssignableRolePlace place} already has an {@link AssignableRole role}
* with the associated {@link AEmote emote}
*/
boolean hasAssignableRolePlaceEmote(AssignableRolePlace place, AEmote emote);
CompletableFuture<Void> removeRoleFromAssignableRolePlace(AServer server, String placeName, ARole role);
/**
* Whether or not the {@link AssignableRolePlace place} has the position used. Each of the {@link AssignableRole roles}
* in the {@link AssignableRolePlace place} has a position in which it is posted. This is used to order the roles when posting them. This position is an {@link Integer integer}
* and it is not guaranteed every position up until the amount of {@link AssignableRole roles} is used.
* There can be spots, it is only used as an ordering and to swap/move {@link AssignableRole roles}
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} should be in
* @param placeName The key of the {@link AssignableRolePlace place}
* @param position The position of an {@link AssignableRole role} within the place
* @return Whether or not there exists an {@link AssignableRole role} within the
* {@link AssignableRolePlace place} identified by the {@link AServer server} and key
*/
boolean isPositionUsed(AServer server, String placeName, Integer position);
/**
* Sets the {@link AssignableRole role} identified by the
* {@link FullEmote emote} to the given {@link Integer position} in the {@link AssignableRolePlace place} identified by the
* {@link AServer server} and key.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} should be
* @param placeName The key of the {@link AssignableRolePlace place}
* @param emote The {@link FullEmote emote} which identifies the {@link AssignableRole role}
* which position should be changed
* @param position The new position of the {@link AssignableRole role}
* within the place
* @throws AbstractoTemplatedException if the position is already used or the {@link FullEmote emote} has not associated {@link AssignableRole role}
* within the place
*/
void setEmoteToPosition(AServer server, String placeName, FullEmote emote, Integer position);
/**
* Adds the given {@link ARole role} to the {@link AssignableRolePlace place} identified by the {@link AServer server} and key
* in the form as a {@link AssignableRole role}. This role is identified
* by the given {@link FullEmote emote} and has the description. If the {@link AssignableRolePlace place} is already setup, this will
* try to update the message: adding the field and the reaction. This might not always work e.g. the reaction limit was reached.
* If the update is successful, it will also store the updates in the database.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is present
* @param placeName The key of the {@link AssignableRolePlace place}
* @param role The {@link ARole role} which should be awarded when reacting with the given {@link FullEmote emote}
* @param emote The {@link FullEmote emote} which should be placed on the {@link Message message}
* to react to and identify the {@link AssignableRole}
* for this place
* @param description The description which will be displayed in the {@link Message message}
* which has the reactions
* @throws dev.sheldan.abstracto.core.exception.EmoteNotUsableException in case the {@link net.dv8tion.jda.api.entities.Emote emote}
* cannot be used by the current user. This might be an issue, if its from an external {@link net.dv8tion.jda.api.entities.Guild}
* the user is not a part of.
* @return A {@link CompletableFuture future} when the {@link Message message} has been updated
* and the {@link MessageReaction reaction} has been added. Only tries to execute this, in case there
* {@link AssignableRolePlacePost posts} known.
*/
CompletableFuture<Void> addRoleToAssignableRolePlace(AServer server, String placeName, ARole role, FullEmote emote, String description);
/**
* Removes the given {@link AssignableRole role} from the {@link AssignableRolePlace place}
* identified by the {@link AServer server} and the key. The {@link AssignableRole role} is identified
* by the {@link FullEmote emote} which is associated to it. If there are already {@link AssignableRolePlacePost posts}
* for this {@link AssignableRolePlace place} this will remove the {@link MessageReaction reaction} and
* edit the {@link Message message}. If not, the method returns immediately. If the update
* was successful or was not necessary, the data will be updated in the database as well.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param placeName The key of the {@link AssignableRolePlace place} to remove an {@link AssignableRole role}
* from
* @param emote The {@link FullEmote fullEmote} which has an {@link AEmote emote} to identify the {@link AssignableRole role}
* to remove
* @return A {@link CompletableFuture future} which completes when the {@link MessageReaction reaction}
* was removed and the {@link Message message} updated and the database updated, or, if no post is present, only if the database was updated
*/
CompletableFuture<Void> removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote);
/**
* This method is used to setup the {@link AssignableRolePlacePost} for an
* {@link AssignableRolePlace place}. If there are previous {@link AssignableRolePlacePost posts},
* this method will delete them first. This method does not do the rendering, but is only the entry point for the process.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key which identifies the {@link AssignableRolePlace place} within the {@link AServer server}
* @return A {@link CompletableFuture future} which completes if the complete setup is finished successfully.
*/
CompletableFuture<Void> setupAssignableRolePlace(AServer server, String name);
/**
* This method is used to update the {@link AssignableRolePlacePost posts}
* of the {@link AssignableRolePlace place} identified by the {@link AServer server} and the key. This
* effectively re-renders the template for an {@link AssignableRolePlace place} and updates the existing
* {@link AssignableRolePlacePost posts} accordingly. In case there are no posts, this method returns immediately.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @throws ChannelNotInGuildException if the channel which contained the posts does not exist anymore
* @return A {@link CompletableFuture future} which completes successfully if *every* update was successful.
*/
CompletableFuture<Void> refreshAssignablePlacePosts(AServer server, String name);
/**
* This method is used to update the {@link AssignableRolePlacePost posts}
* of the {@link AssignableRolePlace place}. This effectively re-renders the template for an
* {@link AssignableRolePlace place} and updates the existing {@link AssignableRolePlacePost posts} accordingly.
* In case there are no posts, this method returns immediately.
* @param place The {@link AssignableRolePlace place} which should have their {@link Message messages} were updated
* @throws ChannelNotInGuildException if the channel which contained the posts does not exist anymore
* @return A {@link CompletableFuture future} which completes successfully if *every* update was successful.
*/
CompletableFuture<Void> refreshAssignablePlacePosts(AssignableRolePlace place);
/**
* This method updates the first {@link AssignableRolePlacePost posts} which contains the description of the
* {@link AssignableRolePlace place}. If there are no posts, this method will return immediately
* @param place The {@link AssignableRolePlace place} to update the
* @throws ChannelNotInGuildException if the channel which contained the post does not exist anymore
* @return A {@link CompletableFuture future} which completes when the update of the {@link Message message}
* was completed
*/
CompletableFuture<Void> refreshTextFromPlace(AssignableRolePlace place);
/**
* Sets the active attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param newValue The new vale of the active attribute
*/
void setAssignablePlaceActiveTo(AServer server, String name, Boolean newValue);
CompletableFuture<Void> setAssignablePlaceActiveTo(AServer server, String name, Boolean newValue);
/**
* Activates the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place} to activate
*/
void activateAssignableRolePlace(AServer server, String name);
CompletableFuture<Void> activateAssignableRolePlace(AServer server, String name);
/**
* Activates the {@link AssignableRolePlace place}, which means that the activate attribute will be set to true
* @param place The {@link AssignableRolePlace place} to activate
*/
void activateAssignableRolePlace(AssignableRolePlace place);
CompletableFuture<Void> activateAssignableRolePlace(AssignableRolePlace place);
/**
* De-activates the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place} to de-activate
*/
void deactivateAssignableRolePlace(AServer server, String name);
CompletableFuture<Void> deactivateAssignableRolePlace(AServer server, String name);
/**
* De-activates the {@link AssignableRolePlace place}, which means that the activate attribute will be set to false
* @param place The {@link AssignableRolePlace place} to de-activate
*/
void deactivateAssignableRolePlace(AssignableRolePlace place);
CompletableFuture<Void> deactivateAssignableRolePlace(AssignableRolePlace place);
/**
* Sets the inline attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key. This method will update any existing {@link AssignableRolePlacePost posts} of the place, if there
* are any.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param newValue The new vale of the inline attribute
* @return A {@link CompletableFuture future} which completes when the config has been updated, or when the message was edited (if the posts already exist)
*/
CompletableFuture<Void> setAssignablePlaceInlineTo(AServer server, String name, Boolean newValue);
/**
* Sets the inline attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key to true. This method will update any existing {@link AssignableRolePlacePost posts} of the place, if there
* are any.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place} to inline
* @return A {@link CompletableFuture future} which completes when the config has been updated, or when the message was edited (if the posts already exist)
*/
CompletableFuture<Void> inlineAssignableRolePlace(AServer server, String name);
/**
* Sets the inline attribute of the {@link AssignableRolePlace place} to true. This method will update any existing
* {@link AssignableRolePlacePost posts} of the place, if there are any.
* @param place The {@link AssignableRolePlace place} to inline
* @return A {@link CompletableFuture future} which completes when the config has been updated, or when the message was edited (if the posts already exist)
*/
CompletableFuture<Void> inlineAssignableRolePlace(AssignableRolePlace place);
/**
* Sets the inline attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key to false. This method will update any existing {@link AssignableRolePlacePost posts} of the place, if there
* are any.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place} to spread
* @return A {@link CompletableFuture future} which completes when the config has been updated, or when the message was edited (if the posts already exist)
*/
CompletableFuture<Void> spreadAssignableRolePlace(AServer server, String name);
/**
* Sets the inline attribute of the {@link AssignableRolePlace place} to false. This method will update any existing
* {@link AssignableRolePlacePost posts} of the place, if there are any.
* @param place The {@link AssignableRolePlace place} to spread
* @return A {@link CompletableFuture future} which completes when the config has been updated, or when the message was edited (if the posts already exist)
*/
CompletableFuture<Void> spreadAssignableRolePlace(AssignableRolePlace place);
/**
* Sets the unique attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param newValue The new vale of the unique attribute
*/
void setAssignablePlaceUniqueTo(AServer server, String name, Boolean newValue);
/**
* Sets the unique attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key to true.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place} to activate unique role handling
*/
void uniqueAssignableRolePlace(AServer server, String name);
/**
* Sets the unique attribute of the {@link AssignableRolePlace place} to true.
* @param place The {@link AssignableRolePlace place} to activate unique role handling
*/
void uniqueAssignableRolePlace(AssignableRolePlace place);
/**
* Sets the unique attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key to false.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place} to disable unique role handling
*/
void multipleAssignableRolePlace(AServer server, String name);
/**
* Sets the unique attribute of the {@link AssignableRolePlace place} to false.
* @param place The {@link AssignableRolePlace place} to disable unique role handling
*/
void multipleAssignableRolePlace(AssignableRolePlace place);
/**
* Sets the auto-remove attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param newValue The new vale of the auto-remove attribute
*/
void setAssignablePlaceAutoRemoveTo(AServer server, String name, Boolean newValue);
/**
* Sets the auto-remove attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key to true.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place} to activate the automatic removal of reactions
*/
void autoRemoveAssignableRolePlace(AServer server, String name);
/**
* Sets the auto-remove attribute of the {@link AssignableRolePlace place} to true.
* @param place The {@link AssignableRolePlace place} to activate the automatic removal of reactions
*/
void autoRemoveAssignableRolePlace(AssignableRolePlace place);
/**
* Sets the auto-remove attribute of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and the key to false.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place} to keep reactions
*/
void keepReactionsAssignableRolePlace(AServer server, String name);
/**
* Sets the auto-remove attribute of the {@link AssignableRolePlace place} to false.
* @param place The {@link AssignableRolePlace place} to keep reactions
*/
void keepReactionsAssignableRolePlace(AssignableRolePlace place);
/**
* Swaps the positions of the two {@link AssignableRole roles} identified by the respective
* {@link FullEmote emote}. This will only update the it in the database, and require a new setup. The
* two {@link FullEmote emotes} are assumed to be different
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param firstEmote The {@link FullEmote emote} which identifies the first {@link AssignableRole role} to swap
* @param secondEmote The {@link FullEmote emote} which identifies the second {@link AssignableRole role} to swap
* @throws EmoteNotInAssignableRolePlaceException if either one of them is not part of the {@link AssignableRolePlace place}
*
*/
void swapPositions(AServer server, String name, FullEmote firstEmote, FullEmote secondEmote);
/**
* This method renders the {@link AssignableRolePlace place} and post the created {@link MessageToSend messageToSend}
* in the current channel.
* @param server The {@link AServer server} of the {@link AssignableRolePlace place} to test
* @param name The key of the {@link AssignableRolePlace place}
* @param channel The {@link TextChannel channel} in which the resulting {@link MessageToSend messageToSend}
* should be posted in
* @return A {@link CompletableFuture future} which completes when all {@link MessageToSend messageToSend}
* have been sent
*/
CompletableFuture<Void> testAssignableRolePlace(AServer server, String name, TextChannel channel);
/**
* This method renders the configuration of the {@link AssignableRolePlace place} identified by {@link AServer server}
* and key into an {@link MessageToSend messageToSend} and sends a message to the given {@link TextChannel channel}.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param channel The {@link TextChannel channel} in which the resulting {@link MessageToSend messageToSend} should be posted in
* @return A {@link CompletableFuture future} which completes when the {@link MessageToSend} has been sent
*/
CompletableFuture<Void> showAssignablePlaceConfig(AServer server, String name, TextChannel channel);
/**
* Changes the {@link AChannel channel} of the {@link AssignableRole place} identified by {@link AServer server}
* and key to the given {@link TextChannel channel}. This only changes the configuration and does not impact
* any currently posted {@link AssignableRolePlacePost posts}
* @param name The key of the {@link AssignableRolePlace place}
* @param newChannel The {@link TextChannel channel} where the {@link AssignableRolePlace place} should be posted to.
*/
void moveAssignableRolePlace(String name, TextChannel newChannel);
CompletableFuture<Void> moveAssignableRolePlace(AServer server, String name, TextChannel newChannel);
/**
* Deletes the {@link AssignableRolePlace place} identified by {@link AServer server} and key. This method will first
* delete all the {@link AssignableRolePlacePost posts} and then remove the references from the database.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @return A {@link CompletableFuture future} which completes after all posts have been deleted
*/
CompletableFuture<Void> deleteAssignableRolePlace(AServer server, String name);
/**
* Changes the text of an {@link AssignableRolePlace place} in the database only.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param newText The new value for the text attribute displayed in the first {@link AssignableRolePlacePost post}
*/
void changeText(AServer server, String name, String newText);
/**
* Changes the text of an {@link AssignableRolePlace place} in the database, and updates the first
* {@link AssignableRolePlacePost post}. The update of the post happens after the change in the database.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param newText The new value for the text attribute displayed in the first {@link AssignableRolePlacePost post}
* @return A {@link CompletableFuture future} which completes when the config has been updated, or when the message was edited (if the posts already exist)
*/
CompletableFuture<Void> changeTextAsync(AServer server, String name, String newText);
/**
* Removes the reactions and the roles from the user from the place, this does not touch the stored data
* @param place The {@link AssignableRolePlace place} to which remove the existing reactions and roles from
* @param user The {@link AssignedRoleUser user} to the remove *all* reactions and assigned roles from
* @return A {@link CompletableFuture future} which completes when both of these actions have been done for all {@link AssignableRole assignableRoles}
*/
CompletableFuture<Void> removeExistingReactionsAndRoles(AssignableRolePlace place, AssignedRoleUser user);
CompletableFuture<Void> changeConfiguration(AServer server, String name, AssignableRolePlaceParameterKey keyToChange, String newValue);
/**
* Changes the configuration of the given {@link AssignableRolePlaceParameterKey key} to the given value of the
* {@link AssignableRolePlace place} identified by {@link AServer server} and key. If it can be updated immediately,
* this will update the {@link AssignableRolePlacePost posts} and the return {@link CompletableFuture future}
* will return afterwards. This is the case for {@link AssignableRolePlaceParameterKey#INLINE}. The rest of the
* keys will only update the configuration in the database, and the place needs a refresh at a later point.
* @param server The {@link AServer server} in which the {@link AssignableRolePlace place} is
* @param name The key of the {@link AssignableRolePlace place}
* @param keyToChange The {@link AssignableRolePlaceParameterKey key} to change
* @param newValue The new value of the attribute, but be able to convert to a boolean via {@link org.apache.commons.lang3.BooleanUtils#toBooleanObject(String)}
* @return A {@link CompletableFuture future} which completes when the configuration has been completed
*/
CompletableFuture<Void> changeConfiguration(AServer server, String name, AssignableRolePlaceParameterKey keyToChange, Object newValue);
/**
* Retrieves all {@link AssignableRolePlace places}, renders them into {@link MessageToSend messageToSend} and sends
* this message to the given {@link TextChannel channel}.
* @param server The {@link AServer server} for which the {@link AssignableRolePlace places} should be shown for
* @param channel The {@link TextChannel channel} to send the {@link MessageToSend messageToSend} in
* @return A {@link CompletableFuture future} which completes when the message has been sent
*/
CompletableFuture<Void> showAllAssignableRolePlaces(AServer server, TextChannel channel);
}

View File

@@ -2,9 +2,10 @@ package dev.sheldan.abstracto.assignableroles.service;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import java.util.concurrent.CompletableFuture;
@@ -21,13 +22,6 @@ public interface AssignableRoleService {
*/
CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member member);
/**
* Adds the given {@link AssignableRole assignableRole} to the given {@link ServerUser serverUser}
* @param assignableRoleId The ID of the {@link AssignableRole} to add
* @param serverUser The {@link ServerUser serverUser} who should receive the {@link AssignableRole role}
* @return A {@link CompletableFuture future} which completes when the {@link net.dv8tion.jda.api.entities.Role role} was added to the {@link ServerUser serverUser}
*/
CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, ServerUser serverUser);
/**
* Clears all {@link AssignableRole assignableRoles} which are currently given to the {@link AUserInAServer user} of a certain
@@ -37,16 +31,6 @@ public interface AssignableRoleService {
*/
void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer user);
/**
* Assigns the given {@link AssignableRole role} to the {@link Member member} and stores the assignment as a
* {@link dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser}
* @param assignableRoleId The ID of an {@link AssignableRole assignableRole} to be added to the {@link Member member}
* @param toAdd The {@link Member member} to add the role to
* @return A {@link CompletableFuture future} which completes when the {@link net.dv8tion.jda.api.entities.Role role} has
* been added and the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser user} has been persisted
*/
CompletableFuture<Void> fullyAssignAssignableRoleToUser(Long assignableRoleId, Member toAdd);
/**
* Removes the {@link AssignableRole role} from the given {@link Member member}
* @param assignableRole The {@link AssignableRole role} to remove
@@ -65,32 +49,6 @@ public interface AssignableRoleService {
*/
CompletableFuture<Void> removeAssignableRoleFromUser(Long assignableRoleId, Member member);
/**
* Removes the {@link AssignableRole role} from the given {@link AUserInAServer aUserInAServer}
* @param assignableRole The {@link AssignableRole role} to remove
* @param aUserInAServer The {@link AUserInAServer aUserInAServer} to remove the {@link AssignableRole role} from
* @return A {@link CompletableFuture future} which completes when the {@link net.dv8tion.jda.api.entities.Role role}
* has been removed from the {@link AUserInAServer aUserInAServer}
*/
CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer);
/**
* Removes the given {@link AssignableRole role} from the {@link ServerUser serverUser} and stores the assignment as a
* {@link dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser}
* @param assignableRole The {@link AssignableRole assignableRole} to be removed from the {@link ServerUser serverUser}
* @param serverUser The {@link ServerUser serverUser} to remove the role from
* @return A {@link CompletableFuture future} which completes when the {@link net.dv8tion.jda.api.entities.Role role} has
* been removed and the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser user} has been persisted
*/
CompletableFuture<Void> fullyRemoveAssignableRoleFromUser(AssignableRole assignableRole, ServerUser serverUser);
/**
* Adds the {@link AssignableRole assignableRole} to the given {@link AUserInAServer userInAServer} in the database
* @param assignableRoleId The ID of the {@link AssignableRole role} to be added
* @param aUserInAServer The {@link AUserInAServer user} to get the {@link AssignableRole role}
*/
void addRoleToUser(Long assignableRoleId, AUserInAServer aUserInAServer);
/**
* Adds the {@link AssignableRole assignableRole} to the given {@link AUserInAServer userInAServer} in the database
* @param assignableRole The {@link AssignableRole role} to be added
@@ -105,10 +63,8 @@ public interface AssignableRoleService {
*/
void removeRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer);
/**
* Removes the {@link AssignableRole assignableRole} from the given {@link AUserInAServer userInAServer} in the database
* @param assignableRoleId The ID of the {@link AssignableRole role} to be removed
* @param aUserInAServer The {@link AUserInAServer user} to get the {@link AssignableRole role} removed
*/
void removeRoleFromUser(Long assignableRoleId, AUserInAServer aUserInAServer);
AssignableRole getAssignableRoleInPlace(AssignableRolePlace place, Role role);
AssignableRole getAssignableRoleInPlace(AssignableRolePlace place, ARole role);
AssignableRole getAssignableRoleInPlace(AssignableRolePlace place, Long roleId);
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.assignableroles.service.management;
import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleConditionType;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRoleCondition;
import java.util.Optional;
public interface AssignableRoleConditionManagementService {
AssignableRoleCondition createAssignableRoleCondition(AssignableRole assignableRole, AssignableRoleConditionType type, String value);
void deleteAssignableRoleCondition(AssignableRoleCondition condition);
Optional<AssignableRoleCondition> findAssignableRoleCondition(AssignableRole role, AssignableRoleConditionType type);
}

View File

@@ -2,68 +2,14 @@ package dev.sheldan.abstracto.assignableroles.service.management;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlacePost;
import dev.sheldan.abstracto.core.models.cache.CachedEmote;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.ARole;
import net.dv8tion.jda.api.entities.MessageReaction;
import dev.sheldan.abstracto.core.models.FullEmote;
import dev.sheldan.abstracto.core.models.database.ComponentPayload;
import net.dv8tion.jda.api.entities.Role;
/**
* Management service for the table of {@link AssignableRole assignableRoles}
*/
public interface AssignableRoleManagementService {
/**
* Adds the given {@link ARole role} to the {@link AssignableRolePlace place} to be identified with the given {@link AEmote emote}
* and displayed with the given description. An optional {@link AssignableRolePlacePost post} can be provided, if the
* place has already been setup.
* @param place The {@link AssignableRolePlace place} to add the the {@link ARole role} to
* @param emote The {@link AEmote emote} which is used as an reaction on the {@link AssignableRolePlacePost post}
* @param role The {@link ARole role} which should be given to the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} placing a reaction
* @param description The description which should be displayed in the field for the given {@link ARole role}
* @param post If a {@link AssignableRolePlacePost post} already exists, it can be provided to link the newly created {@link AssignableRole directly}
* @return The created instance of the {@link AssignableRole assignableRole} according to the given parameters
*/
AssignableRole addRoleToPlace(AssignableRolePlace place, AEmote emote, ARole role, String description, AssignableRolePlacePost post);
AssignableRole addRoleToPlace(FullEmote emote, Role role, String description, AssignableRolePlace place, ComponentPayload componentPayload);
/**
* Adds the {@link ARole role} (identified by its ID) to the {@link AssignableRolePlace place} (identified by its ID),
* which in turn is identified by the given {@link AEmote emote} (identified by its ID) and displayed with the given description.
* An optional {@link AssignableRolePlacePost post} can be provided (identified by the ID of the {@link net.dv8tion.jda.api.entities.Message}), if
* it already exists
* @param placeId The ID of the {@link AssignableRolePlace} to add an {@link AssignableRole assignableRole} to
* @param emoteId The ID of the {@link AEmote emote} which should be used as an reaction on the {@link AssignableRolePlacePost post}
* @param roleId The ID of the {@link ARole role} which should be given to the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} placing a reaction
* @param description The description which should be displayed in the field for the given {@link ARole role}
* @param messageId If provided, this message ID will be used to identify the {@link AssignableRolePlacePost post} which already exists
* @return The created instance of the {@link AssignableRole assignableRole} according to the given parameters
*/
AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description, Long messageId);
/**
* Adds the {@link ARole role} (identified by its ID) to the {@link AssignableRolePlace place} (identified by its ID),
* which in turn is identified by the given {@link AEmote emote} (identified by its ID) and displayed with the given description.
* @param placeId The ID of the {@link AssignableRolePlace} to add an {@link AssignableRole assignableRole} to
* @param emoteId The ID of the {@link AEmote emote} which should be used as an reaction on the {@link AssignableRolePlacePost post}
* @param roleId The ID of the {@link ARole role} which should be given to the {@link dev.sheldan.abstracto.core.models.database.AUserInAServer user} placing a reaction
* @param description The description which should be displayed in the field for the given {@link ARole role}
* @return The created instance of the {@link AssignableRole assignableRole} according to the given parameters
*/
AssignableRole addRoleToPlace(Long placeId, Integer emoteId, Long roleId, String description);
/**
* Finds the {@link AssignableRole} given by the ID and returns it if found. Throws an exception otherwise.
* @param assignableRoleId The ID Of the {@link AssignableRole assignableRole} to find
* @return An instance of {@link AssignableRole assignableRole} if it exists for the given ID
*/
AssignableRole getByAssignableRoleId(Long assignableRoleId);
void deleteAssignableRole(AssignableRole assignableRole);
/**
* Returns the respective {@link AssignableRole assignableRole} for the {@link CachedEmote emote} which is part of the
* {@link AssignableRolePlace place}. It will throw an exception, if the {@link CachedEmote emote} is not used.
* @param cachedEmote The {@link CachedEmote emote} which should be used to identify the {@link AssignableRole role}
* @param assignableRolePlace The {@link AssignableRolePlace place} from which the {@link AssignableRole role} should be retrieved for
* @return An instance of {@link AssignableRole role} which was in the place and identified by the emote
*/
AssignableRole getRoleForReactionEmote(CachedEmote cachedEmote, AssignableRolePlace assignableRolePlace);
AssignableRole getRoleForReactionEmote(MessageReaction.ReactionEmote cachedEmote, AssignableRolePlace assignableRolePlace);
}

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