mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-18 14:17:56 +00:00
Compare commits
134 Commits
abstracto-
...
abstracto-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
063581ba1a | ||
|
|
5c7b018b2a | ||
|
|
d315113395 | ||
|
|
ea2f62b721 | ||
|
|
1a91275a2d | ||
|
|
e76b22ca59 | ||
|
|
5a21f9642c | ||
|
|
e3dd89b0ef | ||
|
|
4fe81c0ea2 | ||
|
|
ab55f5ee07 | ||
|
|
92cec30898 | ||
|
|
3a40ccccda | ||
|
|
e6802a0851 | ||
|
|
ce90370b9c | ||
|
|
b21afce1ad | ||
|
|
58fd11a561 | ||
|
|
3e38085a25 | ||
|
|
48f62f8bdf | ||
|
|
ad92ccd181 | ||
|
|
8ab0eaedda | ||
|
|
e2a7d3b9e8 | ||
|
|
8c101793a3 | ||
|
|
4e1f9e0018 | ||
|
|
102209aaca | ||
|
|
9a64da480b | ||
|
|
11c36691ce | ||
|
|
337ef87e47 | ||
|
|
056a7fe297 | ||
|
|
82383449c0 | ||
|
|
30655dbfef | ||
|
|
a43725df39 | ||
|
|
9a0bff154b | ||
|
|
4d54b11400 | ||
|
|
9c621954c8 | ||
|
|
f24552fdf2 | ||
|
|
e643080516 | ||
|
|
b747516881 | ||
|
|
0a4238c9f5 | ||
|
|
99fe84914b | ||
|
|
f9b85feeaf | ||
|
|
51edb50eee | ||
|
|
43a78a4989 | ||
|
|
e3e0ad98ba | ||
|
|
9c02be7299 | ||
|
|
9954515db0 | ||
|
|
68cae74819 | ||
|
|
1a1fde0800 | ||
|
|
74cee39f1a | ||
|
|
5ad3e30cc1 | ||
|
|
c02bf4aa8e | ||
|
|
c84a76b6a3 | ||
|
|
120df02dd0 | ||
|
|
61f43f6bc9 | ||
|
|
982cbb82d7 | ||
|
|
b4627d1ab0 | ||
|
|
1d6de3f1e8 | ||
|
|
1913bc930d | ||
|
|
09450429dd | ||
|
|
17470f9718 | ||
|
|
91a23f870c | ||
|
|
b047d3eb49 | ||
|
|
db5b420f0a | ||
|
|
a7e60f6338 | ||
|
|
eed90c1406 | ||
|
|
78027ee980 | ||
|
|
e35071d8d5 | ||
|
|
14865a32f2 | ||
|
|
ae3c66384f | ||
|
|
986b65a1e4 | ||
|
|
cc898b27bb | ||
|
|
9ce07a1a4a | ||
|
|
ee01a3f07c | ||
|
|
9230a13218 | ||
|
|
c248351721 | ||
|
|
b0376778fe | ||
|
|
7f5d17e4dc | ||
|
|
0e7ea25aef | ||
|
|
f2aa7035aa | ||
|
|
c10296251c | ||
|
|
15fb9d95a8 | ||
|
|
79633d7a8e | ||
|
|
cef46737c5 | ||
|
|
c7076795a2 | ||
|
|
9e1527ccd1 | ||
|
|
326d488059 | ||
|
|
a39b6695a6 | ||
|
|
362d87778e | ||
|
|
0514d355c7 | ||
|
|
8909e8ebe5 | ||
|
|
36ca9b11e4 | ||
|
|
4a66b7fc67 | ||
|
|
b2a94059e2 | ||
|
|
16e6caa1f0 | ||
|
|
da1a71ecdc | ||
|
|
0646efe33d | ||
|
|
db856f2647 | ||
|
|
1d85eb1e7e | ||
|
|
5e6999cd45 | ||
|
|
9659a3487a | ||
|
|
6d27c487f2 | ||
|
|
8ac3b327e4 | ||
|
|
448332f24f | ||
|
|
d7f889971d | ||
|
|
69abff77fb | ||
|
|
2c31fa1c1e | ||
|
|
19a4858da1 | ||
|
|
3ed1f0c54a | ||
|
|
d01e46a9a6 | ||
|
|
222250b795 | ||
|
|
9a87b75998 | ||
|
|
b16cef0d3c | ||
|
|
cc55934ff2 | ||
|
|
168b4a52c8 | ||
|
|
73b5684a7e | ||
|
|
23ba9a88aa | ||
|
|
a5664946e1 | ||
|
|
ec16548cea | ||
|
|
9c9082034a | ||
|
|
1486a0e9c3 | ||
|
|
533f1afcd5 | ||
|
|
a6c3bb5aa2 | ||
|
|
5311cfcc2e | ||
|
|
ee7f9180dc | ||
|
|
3f67593ef4 | ||
|
|
0ccee3b211 | ||
|
|
86b9ccb164 | ||
|
|
bc1eb0b55f | ||
|
|
92a8b5ba64 | ||
|
|
7535b2e66d | ||
|
|
7117ac26d3 | ||
|
|
32056cd6b9 | ||
|
|
efd6c23713 | ||
|
|
794fc7ceac | ||
|
|
6b5a255aa8 |
42
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Bug Report
|
||||
description: Found a bug that needs fixing?
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: General Troubleshooting
|
||||
description: You confirm to have made the following checks first.
|
||||
options:
|
||||
- label: I have checked for similar issues on the Issue-tracker.
|
||||
required: true
|
||||
- label: I have updated to the latest version
|
||||
required: true
|
||||
- label: I have checked the branches or the maintainers' PRs for upcoming bug fixes.
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Description"
|
||||
description: "General information about the bug"
|
||||
placeholder: "..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Steps to reproduce"
|
||||
description: "What happened when the bug occurred?"
|
||||
placeholder: "1. ..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Expected behaviour"
|
||||
description: "What should happen?"
|
||||
placeholder: "It should..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Actual behaviour"
|
||||
description: "What did happen instead?"
|
||||
placeholder: "It actually ..."
|
||||
validations:
|
||||
required: true
|
||||
36
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
36
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Feature request
|
||||
description: Want some functionality added?
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: General Information
|
||||
description: You confirm to have made the following checks first.
|
||||
options:
|
||||
- label: I have checked for similar issues on the Issue-tracker.
|
||||
required: true
|
||||
- label: I have updated to the latest version
|
||||
required: true
|
||||
- label: I have checked the branches or the maintainers' PRs for upcoming features fixes.
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Description"
|
||||
description: "General description of the feature"
|
||||
placeholder: "..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Feature worth and general use"
|
||||
description: "Why should this be in abstracto?"
|
||||
placeholder: "..."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Suggestions for implementation"
|
||||
description: "Any ideas about what the feature should behave/look like? Commands?"
|
||||
placeholder: "It should..."
|
||||
validations:
|
||||
required: false
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Sheldan
|
||||
Copyright (c) 2022 Sheldan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -14,7 +14,7 @@ An example implementation of this bot can be seen [here](https://github.com/Shel
|
||||
|
||||
|
||||
## Technologies
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 4.3.0_284
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 5.0.0-alpha.21
|
||||
* [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.
|
||||
|
||||
@@ -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.4.8</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>
|
||||
@@ -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>
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -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.Message;
|
||||
import net.dv8tion.jda.api.entities.channel.ChannelType;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
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.*;
|
||||
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";
|
||||
private static final String LEVEL_CONDITION_SERVER_PARAMETER = "serverId";
|
||||
|
||||
@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;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> processMessage(Message message) {
|
||||
if(message.getMentions().getUsers().size() > maxAllowedMentions) {
|
||||
Integer level = configService.getLongValueOrConfigDefault(MassPingService.MAX_AFFECTED_LEVEL_KEY, message.getGuild().getIdLong()).intValue();
|
||||
boolean allowed = allowedToMassMention(message, level);
|
||||
if(!allowed) {
|
||||
return memberService.timeoutUserMaxDuration(message.getMember())
|
||||
.thenAccept(unused -> self.sendMassPingMuteNotification(message))
|
||||
.thenAccept(unused -> log.info("Muted member {} in server {} because of too many member mentions. (> {}).",
|
||||
message.getAuthor().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.getAuthor().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);
|
||||
parameters.put(LEVEL_CONDITION_SERVER_PARAMETER, message.getGuild().getIdLong());
|
||||
ConditionContextInstance contextInstance = ConditionContextInstance
|
||||
.builder()
|
||||
.conditionName(LEVEL_CONDITION_NAME)
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
SystemCondition.Result result = conditionService.checkConditions(contextInstance);
|
||||
return SystemCondition.Result.consideredSuccessful(result);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> sendMassPingMuteNotification(Message message) {
|
||||
Member member = message.getMember();
|
||||
MassPingNotificationModel model = MassPingNotificationModel
|
||||
.builder()
|
||||
.messageLink(message.getJumpUrl())
|
||||
.mentionCount(message.getMentions().getUsers().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()));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.4.8</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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
17
abstracto-application/abstracto-modules/anti-raid/pom.xml
Normal file
17
abstracto-application/abstracto-modules/anti-raid/pom.xml
Normal 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.4.8</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>
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.assignableroles.command;
|
||||
|
||||
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService;
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
@@ -16,7 +17,7 @@ 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;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -41,11 +42,15 @@ public class CreateAssignableRolePost extends AbstractConditionableCommand {
|
||||
String name = (String) parameters.get(0);
|
||||
TextChannel channel = (TextChannel) parameters.get(1);
|
||||
String text = (String) parameters.get(2);
|
||||
AssignableRolePlaceType type = AssignableRolePlaceType.DEFAULT;
|
||||
if(parameters.size() > 3) {
|
||||
type = (AssignableRolePlaceType) parameters.get(3);
|
||||
}
|
||||
if(!channel.getGuild().equals(commandContext.getGuild())) {
|
||||
throw new EntityGuildMismatchException();
|
||||
}
|
||||
AChannel chosenChannel = channelManagementService.loadChannel(channel.getIdLong());
|
||||
service.createAssignableRolePlace(name, chosenChannel, text);
|
||||
service.createAssignableRolePlace(name, chosenChannel, text, type);
|
||||
return CommandResult.fromSuccess();
|
||||
}
|
||||
|
||||
@@ -54,10 +59,11 @@ public class CreateAssignableRolePost extends AbstractConditionableCommand {
|
||||
List<ParameterValidator> rolePlaceNameValidator = Arrays.asList(MaxStringLengthValidator.max(AssignableRolePlace.ASSIGNABLE_PLACE_NAME_LIMIT));
|
||||
Parameter rolePostName = Parameter.builder().name("name").validators(rolePlaceNameValidator).type(String.class).templated(true).build();
|
||||
Parameter channel = Parameter.builder().name("channel").type(TextChannel.class).templated(true).build();
|
||||
Parameter type = Parameter.builder().name("type").type(AssignableRolePlaceType.class).templated(true).optional(true).build();
|
||||
List<ParameterValidator> rolePlaceDescriptionValidator = Arrays.asList(MaxStringLengthValidator.max(AssignableRolePlace.ASSIGNABLE_PLACE_NAME_LIMIT));
|
||||
Parameter text = Parameter.builder().name("text").validators(rolePlaceDescriptionValidator).type(String.class).remainder(true).optional(true).templated(true).build();
|
||||
Parameter text = Parameter.builder().name("text").validators(rolePlaceDescriptionValidator).type(String.class).templated(true).build();
|
||||
List<String> aliases = Arrays.asList("crRPl", "crAssRoPl");
|
||||
List<Parameter> parameters = Arrays.asList(rolePostName, channel, text);
|
||||
List<Parameter> parameters = Arrays.asList(rolePostName, channel, text, type);
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("createAssignableRolePlace")
|
||||
|
||||
@@ -50,6 +50,7 @@ public class DeleteAssignableRolePlace extends AbstractConditionableCommand {
|
||||
.templated(true)
|
||||
.causesReaction(true)
|
||||
.async(true)
|
||||
.requiresConfirmation(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
|
||||
@@ -12,7 +12,7 @@ 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 net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -48,8 +48,18 @@ public class MoveAssignableRolePlace extends AbstractConditionableCommand {
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
Parameter rolePostName = Parameter.builder().name("name").type(String.class).templated(true).build();
|
||||
Parameter channel = Parameter.builder().name("channel").type(TextChannel.class).templated(true).build();
|
||||
Parameter rolePostName = Parameter
|
||||
.builder()
|
||||
.name("name")
|
||||
.type(String.class)
|
||||
.templated(true)
|
||||
.build();
|
||||
Parameter channel = Parameter
|
||||
.builder()
|
||||
.name("channel")
|
||||
.type(TextChannel.class)
|
||||
.templated(true)
|
||||
.build();
|
||||
List<Parameter> parameters = Arrays.asList(rolePostName, channel);
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.abstracto.assignableroles.command;
|
||||
|
||||
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
|
||||
import dev.sheldan.abstracto.assignableroles.model.template.AssignableRolePlaceConfig;
|
||||
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService;
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
@@ -9,8 +10,9 @@ 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.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -24,21 +26,24 @@ import java.util.concurrent.CompletableFuture;
|
||||
@Component
|
||||
public class ShowAssignableRolePlaceConfig extends AbstractConditionableCommand {
|
||||
|
||||
|
||||
@Autowired
|
||||
private AssignableRolePlaceService service;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
public static final String ASSIGNABLE_ROLES_CONFIG_POST_TEMPLATE_KEY = "assignable_roles_config_post";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
String name = (String) parameters.get(0);
|
||||
AServer server = serverManagementService.loadServer(commandContext.getGuild());
|
||||
// TODO refactor to return something to be posted in this command here instead of relying it to be posted somewhere else
|
||||
return service.showAssignablePlaceConfig(server, name, commandContext.getChannel())
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
AssignableRolePlaceConfig config = service.getAssignableRolePlaceConfig(commandContext.getGuild(), name);
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ASSIGNABLE_ROLES_CONFIG_POST_TEMPLATE_KEY, config, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,7 +56,7 @@ public class ShowAssignableRolePlaceConfig extends AbstractConditionableCommand
|
||||
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.causesReaction(true)
|
||||
.causesReaction(false)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.abstracto.assignableroles.command;
|
||||
|
||||
import dev.sheldan.abstracto.assignableroles.config.AssignableRoleFeatureDefinition;
|
||||
import dev.sheldan.abstracto.assignableroles.model.template.AssignablePlaceOverview;
|
||||
import dev.sheldan.abstracto.assignableroles.service.AssignableRolePlaceService;
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
@@ -9,7 +10,9 @@ 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.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -28,11 +31,16 @@ public class ShowAssignableRolePlaces extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
public static final String ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY = "assignable_role_places_overview";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
AServer server = serverManagementService.loadServer(commandContext.getGuild());
|
||||
return service.showAllAssignableRolePlaces(server, commandContext.getChannel())
|
||||
.thenApply(aVoid -> CommandResult.fromIgnored());
|
||||
AssignablePlaceOverview model = service.getAssignableRolePlaceOverview(commandContext.getGuild());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -42,7 +50,6 @@ public class ShowAssignableRolePlaces extends AbstractConditionableCommand {
|
||||
.name("showAssignableRolePlaces")
|
||||
.module(AssignableRoleModuleDefinition.ASSIGNABLE_ROLES)
|
||||
.templated(true)
|
||||
.causesReaction(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
.help(helpInfo)
|
||||
|
||||
@@ -11,6 +11,7 @@ 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 dev.sheldan.abstracto.core.service.SystemCondition;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -24,6 +25,7 @@ public class AssignableRoleMinimumLevelConditionImpl implements AssignableRoleCo
|
||||
private final String conditionName = "HAS_LEVEL";
|
||||
private final String userIdParameter = "userId";
|
||||
private final String levelParameter = "level";
|
||||
private final String serverParameter = "serverId";
|
||||
|
||||
@Autowired
|
||||
private ConditionService conditionService;
|
||||
@@ -34,13 +36,15 @@ public class AssignableRoleMinimumLevelConditionImpl implements AssignableRoleCo
|
||||
Map<String, Object> parameters = new HashMap<>();
|
||||
parameters.put(userIdParameter, aUserInAServer.getUserInServerId());
|
||||
parameters.put(levelParameter, level);
|
||||
parameters.put(serverParameter, aUserInAServer.getServerReference().getId());
|
||||
|
||||
ConditionContextInstance contextInstance = ConditionContextInstance
|
||||
.builder()
|
||||
.conditionName(conditionName)
|
||||
.parameters(parameters)
|
||||
.build();
|
||||
return conditionService.checkConditions(contextInstance);
|
||||
SystemCondition.Result result = conditionService.checkConditions(contextInstance);
|
||||
return SystemCondition.Result.consideredSuccessful(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,11 +2,13 @@ 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.exception.BoosterAssignableRolePlaceMemberNotBoostingException;
|
||||
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.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
|
||||
import dev.sheldan.abstracto.assignableroles.model.template.AssignableRoleSuccessNotificationModel;
|
||||
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleConditionServiceBean;
|
||||
@@ -17,10 +19,10 @@ import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUser
|
||||
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.interaction.button.listener.ButtonClickedListenerResult;
|
||||
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListener;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.listener.ButtonClickedListenerModel;
|
||||
import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerModel;
|
||||
import dev.sheldan.abstracto.core.service.RoleService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
@@ -29,8 +31,8 @@ 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 net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.components.buttons.ButtonInteraction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -72,10 +74,11 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene
|
||||
|
||||
@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) {
|
||||
ButtonInteractionEvent event = model.getEvent();
|
||||
Member member = event.getMember();
|
||||
if(event.getGuild() != null && member != null) {
|
||||
AssignableRolePlacePayload payload = (AssignableRolePlacePayload) model.getDeserializedPayload();
|
||||
AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(payload.getPlaceId());
|
||||
Guild guild = event.getGuild();
|
||||
List<Role> removedRoles = new ArrayList<>();
|
||||
Role roleById = guild.getRoleById(payload.getRoleId());
|
||||
@@ -88,19 +91,25 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene
|
||||
throw new AssignableRoleNotFoundException(payload.getRoleId());
|
||||
}
|
||||
if(roleById != null) {
|
||||
boolean memberHasRole = event
|
||||
.getMember()
|
||||
boolean memberHasRole = member
|
||||
.getRoles()
|
||||
.stream()
|
||||
.anyMatch(memberRole -> memberRole.getIdLong() == payload.getRoleId());
|
||||
if(!memberHasRole) {
|
||||
if(place.getType().equals(AssignableRolePlaceType.BOOSTER) && member.getTimeBoosted() == null) {
|
||||
assignableRoleService.assignableRoleConditionFailure();
|
||||
throw new BoosterAssignableRolePlaceMemberNotBoostingException();
|
||||
}
|
||||
AssignableRole assignableRole = assignableRoleOptional.get();
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
if(!assignableRole.getConditions().isEmpty()) {
|
||||
log.debug("Evaluating {} conditions for assignable role {}.", assignableRole.getConditions().size(), assignableRole.getId());
|
||||
AssignableRoleConditionResult conditionResult =
|
||||
assignableRoleConditionServiceBean.evaluateConditions(assignableRole.getConditions(), aUserInAServer, roleById);
|
||||
if(!conditionResult.getFulfilled()) {
|
||||
log.info("One condition failed to be fulfilled - notifying user.");
|
||||
self.notifyUserAboutConditionFail(model, event.getInteraction(), conditionResult.getModel());
|
||||
assignableRoleService.assignableRoleConditionFailure();
|
||||
return ButtonClickedListenerResult.ACKNOWLEDGED;
|
||||
}
|
||||
}
|
||||
@@ -116,9 +125,10 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene
|
||||
.map(roleOfUser -> guild.getRoleById(roleOfUser.getRole().getId()))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
log.info("Removing {} because of unique role configuration in place {}.", rolesToRemove.size(), place.getId());
|
||||
removedRoles.addAll(rolesToRemove);
|
||||
List<CompletableFuture<Void>> removalFutures = new ArrayList<>();
|
||||
rolesToRemove.forEach(roleToRemove -> removalFutures.add(roleService.removeRoleFromUserAsync(event.getMember(), roleToRemove)));
|
||||
rolesToRemove.forEach(roleToRemove -> removalFutures.add(roleService.removeRoleFromUserAsync(member, roleToRemove)));
|
||||
removalFuture = new CompletableFutureList<>(removalFutures).getMainFuture();
|
||||
} else {
|
||||
removalFuture = CompletableFuture.completedFuture(null);
|
||||
@@ -126,29 +136,32 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene
|
||||
} else {
|
||||
removalFuture = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
CompletableFuture<Void> roleAdditionFuture = roleService.addRoleToMemberAsync(event.getMember(), roleById);
|
||||
CompletableFuture<Void> roleAdditionFuture = assignableRoleService.assignAssignableRoleToUser(roleById, member);
|
||||
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());
|
||||
roleById.getId(), member.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);
|
||||
log.info("Persisting adding assignable role update for user {} in server {} of role {}.", member.getIdLong(), guild.getIdLong(), roleById.getId());
|
||||
self.persistAssignableUser(member, payload, false);
|
||||
});
|
||||
}
|
||||
}).exceptionally(throwable -> {
|
||||
log.error("Failed to perform role change in assignable role place.", throwable);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
roleService.removeRoleFromUserAsync(event.getMember(), roleById)
|
||||
assignableRoleService.removeAssignableRoleFromUser(roleById, member)
|
||||
.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());
|
||||
roleById.getId(), member.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);
|
||||
log.info("Persisting remove assignable role update for user {} in server {} of role {}.", member.getIdLong(), guild.getIdLong(), roleById.getId());
|
||||
self.persistAssignableUser(member, payload, true);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -183,6 +196,8 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> notifyUser(ButtonClickedListenerModel model, boolean roleAdded, Role role, ButtonInteraction buttonInteraction, List<Role> removedRoles) {
|
||||
log.info("Notifying user {} in server {} in channel {} about role change with role {}.",
|
||||
buttonInteraction.getUser().getIdLong(), buttonInteraction.getGuild().getIdLong(), buttonInteraction.getChannel().getIdLong(), role.getId());
|
||||
AssignableRoleSuccessNotificationModel notificationModel = AssignableRoleSuccessNotificationModel
|
||||
.builder()
|
||||
.added(roleAdded)
|
||||
@@ -196,13 +211,15 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene
|
||||
@Transactional
|
||||
public CompletableFuture<Void> notifyUserAboutConditionFail(ButtonClickedListenerModel model, ButtonInteraction buttonInteraction,
|
||||
AssignableRolePlaceConditionModel conditionModel) {
|
||||
log.info("Notifying user {} in server {} in channel {} about failed condition.", buttonInteraction.getUser().getIdLong(),
|
||||
buttonInteraction.getGuild().getIdLong(), buttonInteraction.getChannel().getIdLong());
|
||||
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);
|
||||
return AssignableRolePlaceServiceBean.ASSIGNABLE_ROLE_COMPONENT_ORIGIN.equals(model.getOrigin()) && model.getEvent().isFromGuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
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.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
|
||||
import dev.sheldan.abstracto.assignableroles.service.AssignableRoleService;
|
||||
import dev.sheldan.abstracto.assignableroles.service.management.AssignableRoleManagementService;
|
||||
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.AsyncMemberBoostTimeUpdateListener;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.listener.BoostTimeUpdatedModel;
|
||||
import dev.sheldan.abstracto.core.service.RoleService;
|
||||
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 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 AssignableRolePlaceBoostTimeUpdateListener implements AsyncMemberBoostTimeUpdateListener {
|
||||
|
||||
@Autowired
|
||||
private AssignedRoleUserManagementService assignedRoleUserManagementService;
|
||||
|
||||
@Autowired
|
||||
private AssignableRoleManagementService assignableRoleManagementService;
|
||||
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private AssignableRoleService assignableRoleService;
|
||||
|
||||
@Autowired
|
||||
private AssignableRolePlaceBoostTimeUpdateListener self;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(BoostTimeUpdatedModel model) {
|
||||
Member member = model.getMember();
|
||||
if(member.getTimeBoosted() == null) {
|
||||
removeAssignedBoosterRoles(member);
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
return DefaultListenerResult.IGNORED;
|
||||
}
|
||||
|
||||
private void removeAssignedBoosterRoles(Member member) {
|
||||
log.info("Member {} in server {} stopped boosting.", member.getIdLong(), member.getGuild().getIdLong());
|
||||
ServerUser serverUser = ServerUser.fromMember(member);
|
||||
Optional<AssignedRoleUser> assignedRoleUserOptional = assignedRoleUserManagementService.findByUserInServerOptional(serverUser);
|
||||
if(assignedRoleUserOptional.isPresent()) {
|
||||
AssignedRoleUser assignedRoleUser = assignedRoleUserOptional.get();
|
||||
List<AssignableRole> boosterRoles = assignableRoleManagementService.getAssignableRolesFromAssignableUserWithPlaceType(assignedRoleUser, AssignableRolePlaceType.BOOSTER);
|
||||
if(!boosterRoles.isEmpty()) {
|
||||
log.info("Removing {} assignable role mappings.", boosterRoles.size());
|
||||
Guild guild = member.getGuild();
|
||||
List<Role> actualRolesToDelete = boosterRoles
|
||||
.stream()
|
||||
.map(assignableRole -> guild.getRoleById(assignableRole.getRole().getId()))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
log.debug("Which translated to {} roles in reality.", actualRolesToDelete.size());
|
||||
List<CompletableFuture<Void>> list = new ArrayList<>();
|
||||
actualRolesToDelete.forEach(role -> list.add(roleService.removeRoleFromUserAsync(member, role)));
|
||||
FutureUtils.toSingleFutureGeneric(list)
|
||||
.thenAccept(unused -> self.clearPersistedBoosterAssignableRoles(member))
|
||||
.exceptionally(throwable -> {
|
||||
log.warn("One or more roles might have failed to remove. ", throwable);
|
||||
self.clearPersistedBoosterAssignableRoles(member);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
log.info("Member {} in server {} did not have boost roles - doing nothing.", member.getIdLong(), member.getGuild().getIdLong());
|
||||
}
|
||||
} else {
|
||||
log.info("Member (ID {}) in server (ID: {}), who was not tracked via assignable roles, stopped boosting - doing nothing.",
|
||||
member.getIdLong(), member.getGuild().getIdLong());
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void clearPersistedBoosterAssignableRoles(Member member) {
|
||||
ServerUser serverUser = ServerUser.fromMember(member);
|
||||
Optional<AssignedRoleUser> assignedRoleUserOptional = assignedRoleUserManagementService.findByUserInServerOptional(serverUser);
|
||||
if(assignedRoleUserOptional.isPresent()) {
|
||||
AssignedRoleUser assignedRoleUser = assignedRoleUserOptional.get();
|
||||
List<AssignableRole> boosterRoles = assignableRoleManagementService.getAssignableRolesFromAssignableUserWithPlaceType(assignedRoleUser, AssignableRolePlaceType.BOOSTER);
|
||||
assignableRoleService.removeAssignableRolesFromAssignableRoleUser(boosterRoles, assignedRoleUser);
|
||||
} else {
|
||||
log.warn("No assigned role user found for member {} in server {}.", member.getIdLong(), member.getGuild().getIdLong());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return AssignableRoleFeatureDefinition.ASSIGNABLE_ROLES;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package dev.sheldan.abstracto.assignableroles.model;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.button.ButtonPayload;
|
||||
import dev.sheldan.abstracto.core.interaction.button.ButtonPayload;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package dev.sheldan.abstracto.assignableroles.repository;
|
||||
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository to manage the access to the table managed by {@link AssignableRole assignableRole}
|
||||
*/
|
||||
@Repository
|
||||
public interface AssignableRoleRepository extends JpaRepository<AssignableRole, Long> {
|
||||
List<AssignableRole> findByAssignedUsersContainingAndAssignablePlace_Type(AssignedRoleUser roleUser, AssignableRolePlaceType type);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ 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 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;
|
||||
@@ -27,6 +28,7 @@ import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AssignableRoleConditionServiceBean implements AssignableRoleConditionService {
|
||||
|
||||
@Autowired
|
||||
@@ -55,12 +57,15 @@ public class AssignableRoleConditionServiceBean implements AssignableRoleConditi
|
||||
|
||||
@Override
|
||||
public AssignableRoleConditionResult evaluateConditions(List<AssignableRoleCondition> conditions, AUserInAServer aUserInAServer, Role role) {
|
||||
log.debug("Evaluating {} conditions for role {}.", conditions.size(), role.getId());
|
||||
for (AssignableRoleCondition condition : conditions) {
|
||||
if(assignableRoleConditionEvaluators != null) {
|
||||
Optional<AssignableRoleConditionEvaluator> evaluatorOptional = findEvaluatorForCondition(condition.getType());
|
||||
if(evaluatorOptional.isPresent()) {
|
||||
AssignableRoleConditionEvaluator evaluator = evaluatorOptional.get();
|
||||
log.debug("Evaluating condition {} with evaluator {}.", condition.getType(), evaluator.getClass());
|
||||
if(!evaluator.fulfillsCondition(condition, aUserInAServer)) {
|
||||
log.info("Condition {} failed for role {} in server {}.", condition.getType(), role.getId(), aUserInAServer.getServerReference().getId());
|
||||
return AssignableRoleConditionResult.fromFail(condition.getType(), evaluator.createNotificationModel(condition, role));
|
||||
}
|
||||
}
|
||||
@@ -94,6 +99,7 @@ public class AssignableRoleConditionServiceBean implements AssignableRoleConditi
|
||||
if(assignableRoleConditionManagementService.findAssignableRoleCondition(assignableRole, type).isPresent()) {
|
||||
throw new AssignableRoleConditionAlreadyExistsException();
|
||||
}
|
||||
log.info("Creating new condition for role {} in place {} in server {}.", place.getId(), role.getId(), role.getGuild().getIdLong());
|
||||
return assignableRoleConditionManagementService.createAssignableRoleCondition(assignableRole, type, value);
|
||||
}
|
||||
|
||||
@@ -106,6 +112,7 @@ public class AssignableRoleConditionServiceBean implements AssignableRoleConditi
|
||||
if(!existingCondition.isPresent()) {
|
||||
throw new AssignableRoleConditionDoesNotExistException();
|
||||
}
|
||||
log.info("Deleting assignable role condition on place {} for role {} in server {}.", place.getId(), role.getId(), role.getGuild().getIdLong());
|
||||
existingCondition.ifPresent(condition -> assignableRoleConditionManagementService.deleteAssignableRoleCondition(condition));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,15 @@ import dev.sheldan.abstracto.assignableroles.exception.*;
|
||||
import dev.sheldan.abstracto.assignableroles.model.AssignableRolePlacePayload;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.model.template.*;
|
||||
import dev.sheldan.abstracto.assignableroles.service.management.*;
|
||||
import dev.sheldan.abstracto.core.command.exception.CommandParameterKeyValueWrongTypeException;
|
||||
import dev.sheldan.abstracto.core.exception.ChannelNotInGuildException;
|
||||
import dev.sheldan.abstracto.core.exception.EmoteNotUsableException;
|
||||
import dev.sheldan.abstracto.core.interaction.ComponentPayloadManagementService;
|
||||
import dev.sheldan.abstracto.core.interaction.ComponentPayloadService;
|
||||
import dev.sheldan.abstracto.core.interaction.ComponentService;
|
||||
import dev.sheldan.abstracto.core.models.FullEmote;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.ARole;
|
||||
@@ -21,10 +25,11 @@ import dev.sheldan.abstracto.core.service.*;
|
||||
import dev.sheldan.abstracto.core.service.management.*;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import net.dv8tion.jda.api.interactions.components.ButtonStyle;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -38,9 +43,7 @@ import java.util.stream.Collectors;
|
||||
@Slf4j
|
||||
public class AssignableRolePlaceServiceBean implements AssignableRolePlaceService {
|
||||
|
||||
public static final String ASSIGNABLE_ROLES_CONFIG_POST_TEMPLATE_KEY = "assignable_roles_config_post";
|
||||
public static final String ASSIGNABLE_ROLES_POST_TEMPLATE_KEY = "assignable_roles_post";
|
||||
public static final String ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY = "assignable_role_places_overview";
|
||||
public static final int MAX_ASSIGNABLE_ROLES_PER_POST = ComponentService.MAX_BUTTONS_PER_ROW * 5;
|
||||
public static final String ASSIGNABLE_ROLE_COMPONENT_ORIGIN = "assignableRoleButton";
|
||||
@Autowired
|
||||
@@ -85,12 +88,18 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
@Autowired
|
||||
private AssignableRoleConditionService assignableRoleConditionService;
|
||||
|
||||
@Autowired
|
||||
private AssignedRoleUserManagementServiceBean assignedRoleUserManagementServiceBean;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Override
|
||||
public void createAssignableRolePlace(String name, AChannel channel, String text) {
|
||||
public void createAssignableRolePlace(String name, AChannel channel, String text, AssignableRolePlaceType type) {
|
||||
if (rolePlaceManagementService.doesPlaceExist(channel.getServer(), name)) {
|
||||
throw new AssignableRolePlaceAlreadyExistsException(name);
|
||||
}
|
||||
rolePlaceManagementService.createPlace(name, channel, text);
|
||||
rolePlaceManagementService.createPlace(name, channel, text, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,6 +107,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
public CompletableFuture<Void> addRoleToAssignableRolePlace(AServer server, String placeName, Role role, FullEmote fakeEmote, String description) {
|
||||
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName);
|
||||
if (assignableRolePlace.getAssignableRoles().size() > MAX_ASSIGNABLE_ROLES_PER_POST) {
|
||||
log.info("Assignable role place {} has already {} roles. Not possible to add more.", assignableRolePlace.getId(), assignableRolePlace.getAssignableRoles().size());
|
||||
throw new AssignableRolePlaceMaximumRolesException();
|
||||
}
|
||||
if (assignableRolePlace.getAssignableRoles().stream().anyMatch(assignableRole -> assignableRole.getRole().getId().equals(role.getIdLong()))) {
|
||||
@@ -109,20 +119,21 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
// it only may be unusable if its a custom emote
|
||||
log.debug("Using custom emote {} to create assignable role {} for assignable role place {} in server {}.",
|
||||
fakeEmote.getEmote().getId(), role.getId(), placeId, serverId);
|
||||
if (!emoteService.isEmoteUsableByBot(fakeEmote.getEmote()) && fakeEmote.getEmote().isAvailable()) {
|
||||
if (!emoteService.isEmoteUsableByBot(fakeEmote.getEmote())) {
|
||||
throw new EmoteNotUsableException(fakeEmote.getEmote());
|
||||
}
|
||||
}
|
||||
log.debug("There are already message posts on for the assignable role place {}.", assignableRolePlace.getId());
|
||||
Optional<TextChannel> channelOptional = channelService.getTextChannelFromServerOptional(server.getId(), assignableRolePlace.getChannel().getId());
|
||||
Optional<GuildMessageChannel> channelOptional = channelService.getMessageChannelFromServerOptional(server.getId(), assignableRolePlace.getChannel().getId());
|
||||
if (channelOptional.isPresent()) {
|
||||
TextChannel textChannel = channelOptional.get();
|
||||
GuildMessageChannel textChannel = channelOptional.get();
|
||||
String buttonId = componentService.generateComponentId();
|
||||
String emoteMarkdown = fakeEmote != null ? fakeEmote.getEmoteRepr() : null;
|
||||
if (assignableRolePlace.getMessageId() != null) {
|
||||
return componentService.addButtonToMessage(assignableRolePlace.getMessageId(), textChannel, buttonId, description, emoteMarkdown, ButtonStyle.PRIMARY)
|
||||
log.debug("Assignable role place {} has already message post with ID {} - updating.", assignableRolePlace.getId(), assignableRolePlace.getMessageId());
|
||||
return componentService.addButtonToMessage(assignableRolePlace.getMessageId(), textChannel, buttonId, description, emoteMarkdown, ButtonStyle.SECONDARY)
|
||||
.thenAccept(message -> self.persistAssignableRoleAddition(placeId, role, description, fakeEmote, buttonId));
|
||||
} else {
|
||||
log.info("Assignable role place {} is not yet setup - only adding role to the database.", assignableRolePlace.getId());
|
||||
self.persistAssignableRoleAddition(placeId, role, description, fakeEmote, buttonId);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
@@ -134,6 +145,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
@Transactional
|
||||
public void persistAssignableRoleAddition(Long placeId, Role role, String description, FullEmote fakeEmote, String componentId) {
|
||||
AssignableRolePlace place = assignableRolePlaceManagementServiceBean.findByPlaceId(placeId);
|
||||
log.info("Adding role {} to assignable role place {} with component ID {}.", role.getId(), place.getId(), componentId);
|
||||
ComponentPayload payload = persistButtonCallback(place, componentId, role.getIdLong());
|
||||
assignableRoleManagementServiceBean.addRoleToPlace(fakeEmote, role, description, place, payload);
|
||||
}
|
||||
@@ -144,6 +156,8 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
Long assignableRolePlaceId = assignableRolePlace.getId();
|
||||
for (AssignableRole assignableRole : assignableRolePlace.getAssignableRoles()) {
|
||||
if (assignableRole.getRole().getId().equals(role.getId())) {
|
||||
log.info("Found {} role to be removed - removing button from place.", role.getId());
|
||||
// TODO we might want to actually remove all the assigned roles as well
|
||||
return removeButtonFromAssignableRolePlace(assignableRole, assignableRolePlace).thenAccept(aVoid ->
|
||||
self.deleteAssignableRoleFromPlace(assignableRolePlaceId, assignableRole.getId())
|
||||
);
|
||||
@@ -154,9 +168,12 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
|
||||
private CompletableFuture<Void> removeButtonFromAssignableRolePlace(AssignableRole assignableRole, AssignableRolePlace assignableRolePlace) {
|
||||
String componentId = assignableRole.getComponentPayload().getId();
|
||||
log.debug("Component ID to remove {} for role {}", componentId, assignableRole.getRole().getId());
|
||||
return channelService.retrieveMessageInChannel(assignableRolePlace.getServer().getId(), assignableRolePlace.getChannel().getId(), assignableRolePlace.getMessageId())
|
||||
.thenCompose(message ->
|
||||
componentService.removeComponentWithId(message, componentId, true)
|
||||
.thenCompose(message -> {
|
||||
log.debug("Updating message {} to remove component with ID {}.", message.getIdLong(), componentId);
|
||||
return componentService.removeComponentWithId(message, componentId, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -171,6 +188,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
.findAny();
|
||||
roleToRemoveOptional.ifPresent(assignableRole -> {
|
||||
ComponentPayload componentPayload = assignableRole.getComponentPayload();
|
||||
assignedRoleUserManagementServiceBean.removeAssignedRoleFromUsers(assignableRole);
|
||||
assignableRoleManagementServiceBean.deleteAssignableRole(assignableRole);
|
||||
componentPayloadManagementService.deletePayload(componentPayload);
|
||||
});
|
||||
@@ -192,16 +210,15 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
if (throwable != null) {
|
||||
log.warn("Not able to delete old messages of assignable role place {} in server {}.", assignablePlaceId, serverId);
|
||||
}
|
||||
try {
|
||||
self.createAssignableRolePlacePost(serverId, assignablePlaceId)
|
||||
.thenAccept(unused1 -> postingFuture.complete(null))
|
||||
.exceptionally(innerThrowable -> {
|
||||
postingFuture.completeExceptionally(innerThrowable);
|
||||
return null;
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
postingFuture.completeExceptionally(ex);
|
||||
}
|
||||
self.createAssignableRolePlacePost(serverId, assignablePlaceId)
|
||||
.thenAccept(unused1 -> postingFuture.complete(null))
|
||||
.exceptionally(innerThrowable -> {
|
||||
postingFuture.completeExceptionally(innerThrowable);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
postingFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
return postingFuture;
|
||||
}
|
||||
@@ -211,7 +228,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
AssignablePostMessage model = prepareAssignablePostMessageModel(place);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model, place.getServer().getId());
|
||||
Long channelId = place.getChannel().getId();
|
||||
Optional<TextChannel> channelOptional = channelService.getTextChannelFromServerOptional(place.getServer().getId(), channelId);
|
||||
Optional<GuildMessageChannel> channelOptional = channelService.getMessageChannelFromServerOptional(place.getServer().getId(), channelId);
|
||||
if (channelOptional.isPresent()) {
|
||||
log.info("Refreshing text for assignable role place {} in channel {} in post {}.", place.getId(), channelId, place.getMessageId());
|
||||
return channelService.editEmbedMessageInAChannel(messageToSend.getEmbeds().get(0), channelOptional.get(), place.getMessageId()).thenCompose(message -> CompletableFuture.completedFuture(null));
|
||||
@@ -232,8 +249,10 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
|
||||
private CompletableFuture<Void> deleteExistingMessagePostsForPlace(AssignableRolePlace assignableRolePlace) {
|
||||
if (assignableRolePlace.getMessageId() != null) {
|
||||
log.info("Deleting old message {} for assignable role place {}.", assignableRolePlace.getMessageId(), assignableRolePlace.getId());
|
||||
return messageService.deleteMessageInChannelInServer(assignableRolePlace.getServer().getId(), assignableRolePlace.getChannel().getId(), assignableRolePlace.getMessageId());
|
||||
} else {
|
||||
log.info("Assignable role place {} was not yet set up - no message ID tracked.", assignableRolePlace.getMessageId());
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
@@ -299,12 +318,11 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> showAssignablePlaceConfig(AServer server, String name, TextChannel channel) {
|
||||
Guild guild = guildService.getGuildById(server.getId());
|
||||
public AssignableRolePlaceConfig getAssignableRolePlaceConfig(Guild guild, String name) {
|
||||
AServer server = serverManagementService.loadServer(guild);
|
||||
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
|
||||
log.info("Showing assignable role place config for place {} in channel {} on server {}.", place.getId(), channel.getId(), server.getId());
|
||||
AssignableRolePlaceConfig configModel = convertPlaceToAssignableRolePlaceConfig(guild, place);
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ASSIGNABLE_ROLES_CONFIG_POST_TEMPLATE_KEY, configModel, channel));
|
||||
log.info("Generating assignable role place config for place {} on server {}.", place.getId(), guild.getIdLong());
|
||||
return convertPlaceToAssignableRolePlaceConfig(guild, place);
|
||||
}
|
||||
|
||||
private AssignableRolePlaceConfig convertPlaceToAssignableRolePlaceConfig(Guild guild, AssignableRolePlace place) {
|
||||
@@ -326,6 +344,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
return AssignableRolePlaceConfig
|
||||
.builder()
|
||||
.roles(roles)
|
||||
.type(place.getType())
|
||||
.placeName(place.getKey())
|
||||
.placeText(place.getText())
|
||||
.uniqueRoles(place.getUniqueRoles())
|
||||
@@ -336,6 +355,8 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
@Override
|
||||
public CompletableFuture<Void> moveAssignableRolePlace(AServer server, String name, TextChannel newChannel) {
|
||||
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
|
||||
log.info("Moving assignable role place {} from channel {} to channel {} in guild {}.",
|
||||
place.getId(), place.getChannel().getId(), newChannel.getId(), newChannel.getGuild().getIdLong());
|
||||
CompletableFuture<Void> oldPostDeletionFuture = deleteExistingMessagePostsForPlace(place);
|
||||
Long serverId = server.getId();
|
||||
Long assignablePlaceId = place.getId();
|
||||
@@ -344,17 +365,16 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
if (throwable != null) {
|
||||
log.warn("Not able to delete old messages of assignable role place {} in server {}.", assignablePlaceId, serverId);
|
||||
}
|
||||
try {
|
||||
self.setupAssignableRolePlaceInChannel(serverId, assignablePlaceId, newChannel)
|
||||
.thenAccept(unused1 -> self.updateAssignableRolePlaceChannel(name, newChannel))
|
||||
.thenAccept(unused1 -> returnFuture.complete(null))
|
||||
.exceptionally(innerThrowable -> {
|
||||
returnFuture.completeExceptionally(innerThrowable);
|
||||
return null;
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
returnFuture.completeExceptionally(ex);
|
||||
}
|
||||
self.setupAssignableRolePlaceInChannel(serverId, assignablePlaceId, newChannel)
|
||||
.thenAccept(unused1 -> self.updateAssignableRolePlaceChannel(name, newChannel))
|
||||
.thenAccept(unused1 -> returnFuture.complete(null))
|
||||
.exceptionally(innerThrowable -> {
|
||||
returnFuture.completeExceptionally(innerThrowable);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
returnFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
|
||||
return returnFuture;
|
||||
@@ -363,13 +383,14 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
@Transactional
|
||||
public void updateAssignableRolePlaceChannel(String name, TextChannel textChannel) {
|
||||
AChannel channel = channelManagementService.loadChannel(textChannel.getIdLong());
|
||||
log.info("Setting assignable role place to channel {}.", textChannel.getIdLong());
|
||||
rolePlaceManagementService.moveAssignableRolePlace(name, channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteAssignableRolePlace(AServer server, String name) {
|
||||
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
|
||||
|
||||
log.info("Deleting assignable role place {}.", place.getId());
|
||||
Long placeId = place.getId();
|
||||
CompletableFuture<Void> deleteFuture = deleteExistingMessagePostsForPlace(place);
|
||||
return deleteFuture.thenAccept(unused -> self.deleteAssignableRolePlaceInDatabase(placeId));
|
||||
@@ -405,25 +426,24 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> showAllAssignableRolePlaces(AServer server, TextChannel channel) {
|
||||
public AssignablePlaceOverview getAssignableRolePlaceOverview(Guild guild) {
|
||||
AServer server = serverManagementService.loadServer(guild);
|
||||
List<AssignableRolePlace> assignableRolePlaces = rolePlaceManagementService.findAllByServer(server);
|
||||
Guild guild = channel.getGuild();
|
||||
List<AssignableRolePlaceConfig> placeConfigs = assignableRolePlaces
|
||||
.stream()
|
||||
.map(place -> convertPlaceToAssignableRolePlaceConfig(guild, place))
|
||||
.collect(Collectors.toList());
|
||||
AssignablePlaceOverview overViewModel = AssignablePlaceOverview
|
||||
log.info("Showing overview over all assignable role places for server {}.", server.getId());
|
||||
return AssignablePlaceOverview
|
||||
.builder()
|
||||
.places(placeConfigs)
|
||||
.build();
|
||||
log.info("Showing overview over all assignable role places for server {} in channel {}.", server.getId(), channel.getId());
|
||||
List<CompletableFuture<Message>> promises = channelService.sendEmbedTemplateInTextChannelList(ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY, overViewModel, channel);
|
||||
return CompletableFuture.allOf(promises.toArray(new CompletableFuture[0]));
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> sendAssignablePostMessage(AssignableRolePlace place, TextChannel channel) {
|
||||
private CompletableFuture<Void> sendAssignablePostMessage(AssignableRolePlace place, GuildMessageChannel channel) {
|
||||
AssignablePostMessage model = prepareAssignablePostMessageModel(place);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model, place.getServer().getId());
|
||||
log.info("Sending message for assignable role place {}.", place.getId());
|
||||
CompletableFuture<Message> postFuture = channelService.sendMessageToSendToChannel(messageToSend, channel).get(0);
|
||||
Long placeId = model.getPlaceId();
|
||||
return postFuture.thenCompose(unused -> {
|
||||
@@ -443,6 +463,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
public void persistAssignablePlaceMessageId(Long placeId, CompletableFuture<Message> messageFuture) {
|
||||
AssignableRolePlace place = assignableRolePlaceManagementServiceBean.findByPlaceId(placeId);
|
||||
Message message = messageFuture.join();
|
||||
log.info("Setting message ID of assignable role place {} to {}.", placeId, message.getIdLong());
|
||||
place.setMessageId(message.getIdLong());
|
||||
}
|
||||
|
||||
@@ -485,13 +506,12 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
|
||||
@Transactional
|
||||
public CompletableFuture<Void> createAssignableRolePlacePost(Long serverId, Long assignablePlaceId) {
|
||||
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId);
|
||||
Optional<TextChannel> channelOptional = channelService.getTextChannelFromServerOptional(serverId, assignableRolePlace.getChannel().getId());
|
||||
Optional<GuildMessageChannel> channelOptional = channelService.getMessageChannelFromServerOptional(serverId, assignableRolePlace.getChannel().getId());
|
||||
if (channelOptional.isPresent()) {
|
||||
TextChannel channel = channelOptional.get();
|
||||
GuildMessageChannel channel = channelOptional.get();
|
||||
log.info("Sending assignable role place posts for place {} in channel {} in server {}.", assignableRolePlace.getId(), channel.getId(), serverId);
|
||||
return sendAssignablePostMessage(assignableRolePlace, channel);
|
||||
} else {
|
||||
log.warn("Channel to create assignable role post in does not exist.");
|
||||
throw new AssignableRolePlaceChannelDoesNotExistException(assignableRolePlace.getChannel().getId(), assignableRolePlace.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@@ -71,14 +72,36 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
|
||||
.tagList(Arrays.asList(MetricTag.getTag(ACTION, "removed")))
|
||||
.build();
|
||||
|
||||
private static final CounterMetric ASSIGNABLE_ROLES_CONDITION_FAILED =
|
||||
CounterMetric
|
||||
.builder()
|
||||
.name(ASSIGNABLE_ROLES_METRIC)
|
||||
.tagList(Arrays.asList(MetricTag.getTag(ACTION, "condition")))
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member member) {
|
||||
metricService.incrementCounter(ASSIGNABLE_ROLES_ASSIGNED);
|
||||
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
|
||||
log.info("Assigning role {} to member {} in server {}.", assignableRoleId, member.getId(), member.getGuild().getId());
|
||||
metricService.incrementCounter(ASSIGNABLE_ROLES_ASSIGNED);
|
||||
return roleService.addRoleToMemberAsync(member, role.getRole());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> assignAssignableRoleToUser(Role role, Member member) {
|
||||
return assignRoleToUser(role.getIdLong(), member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assignableRoleConditionFailure() {
|
||||
metricService.incrementCounter(ASSIGNABLE_ROLES_CONDITION_FAILED);
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> assignRoleToUser(Long roleId, Member member) {
|
||||
metricService.incrementCounter(ASSIGNABLE_ROLES_ASSIGNED);
|
||||
return roleService.addRoleToMemberAsync(member, roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer userInAServer) {
|
||||
Optional<AssignedRoleUser> userOptional = assignedRoleUserManagementServiceBean.findByUserInServerOptional(userInAServer);
|
||||
@@ -102,8 +125,17 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
|
||||
@Override
|
||||
public CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, Member member) {
|
||||
log.info("Removing assignable role {} from user {} in server {}.", assignableRole.getId(), member.getId(), member.getGuild().getId());
|
||||
return removeRoleFromUser(assignableRole.getRole().getId(), member);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> removeAssignableRoleFromUser(Role role, Member member) {
|
||||
return removeRoleFromUser(role.getIdLong(), member);
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> removeRoleFromUser(Long roleId, Member member) {
|
||||
metricService.incrementCounter(ASSIGNABLE_ROLES_REMOVED);
|
||||
return roleService.removeRoleFromMemberAsync(member, assignableRole.getRole());
|
||||
return roleService.removeRoleFromMemberAsync(member, roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,9 +179,17 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
|
||||
throw new AssignableRoleNotFoundException(roleId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAssignableRolesFromAssignableRoleUser(List<AssignableRole> roles, AssignedRoleUser roleUser) {
|
||||
log.info("Removing {} assignable roles from user {} in server {}.", roles.size(), roleUser.getUser().getUserReference().getId(),
|
||||
roleUser.getUser().getServerReference().getId());
|
||||
roles.forEach(assignableRole -> assignedRoleUserManagementServiceBean.removeAssignedRoleFromUser(assignableRole, roleUser));
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
metricService.registerCounter(ASSIGNABLE_ROLES_ASSIGNED, "Assignable roles assigned.");
|
||||
metricService.registerCounter(ASSIGNABLE_ROLES_REMOVED, "Assignable roles removed.");
|
||||
metricService.registerCounter(ASSIGNABLE_ROLES_CONDITION_FAILED, "Assignable roles failed to assign because of condition.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import dev.sheldan.abstracto.assignableroles.model.condition.AssignableRoleCondi
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRole;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRoleCondition;
|
||||
import dev.sheldan.abstracto.assignableroles.repository.AssignableRoleConditionRepository;
|
||||
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 AssignableRoleConditionManagementServiceBean implements AssignableRoleConditionManagementService {
|
||||
|
||||
@Autowired
|
||||
@@ -23,12 +25,14 @@ public class AssignableRoleConditionManagementServiceBean implements AssignableR
|
||||
.type(type)
|
||||
.conditionValue(value)
|
||||
.build();
|
||||
log.info("Creating condition of type {} for assignable role {}", assignableRole.getId(), type);
|
||||
assignableRole.getConditions().add(condition);
|
||||
return repository.save(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteAssignableRoleCondition(AssignableRoleCondition condition) {
|
||||
log.info("Deleting condition {}.", condition.getId());
|
||||
repository.delete(condition);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ 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.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
|
||||
import dev.sheldan.abstracto.assignableroles.repository.AssignableRoleRepository;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.models.FullEmote;
|
||||
@@ -15,6 +17,8 @@ import net.dv8tion.jda.api.entities.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AssignableRoleManagementServiceBean implements AssignableRoleManagementService {
|
||||
@@ -51,8 +55,6 @@ public class AssignableRoleManagementServiceBean implements AssignableRoleManage
|
||||
return roleToAdd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public AssignableRole getByAssignableRoleId(Long assignableRoleId) {
|
||||
return repository.findById(assignableRoleId).orElseThrow(() -> new AbstractoRunTimeException("Assignable role not found"));
|
||||
@@ -60,7 +62,14 @@ public class AssignableRoleManagementServiceBean implements AssignableRoleManage
|
||||
|
||||
@Override
|
||||
public void deleteAssignableRole(AssignableRole assignableRole) {
|
||||
assignableRole.getAssignablePlace().getAssignableRoles().remove(assignableRole);
|
||||
assignableRole.setAssignablePlace(null);
|
||||
repository.delete(assignableRole);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AssignableRole> getAssignableRolesFromAssignableUserWithPlaceType(AssignedRoleUser user, AssignableRolePlaceType type) {
|
||||
return repository.findByAssignedUsersContainingAndAssignablePlace_Type(user, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.assignableroles.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.assignableroles.exception.AssignableRolePlaceNotFoundException;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.repository.AssignableRolePlaceRepository;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
@@ -20,12 +21,18 @@ public class AssignableRolePlaceManagementServiceBean implements AssignableRoleP
|
||||
private AssignableRolePlaceRepository repository;
|
||||
|
||||
@Override
|
||||
public AssignableRolePlace createPlace(String name, AChannel channel, String text) {
|
||||
public AssignableRolePlace createPlace(String name, AChannel channel, String text, AssignableRolePlaceType type) {
|
||||
boolean unique = false;
|
||||
if(type.equals(AssignableRolePlaceType.BOOSTER)) {
|
||||
unique = true;
|
||||
}
|
||||
AssignableRolePlace place = AssignableRolePlace
|
||||
.builder()
|
||||
.channel(channel)
|
||||
.server(channel.getServer())
|
||||
.text(text)
|
||||
.uniqueRoles(unique)
|
||||
.type(type)
|
||||
.key(name)
|
||||
.build();
|
||||
log.info("Creating assignable role place in channel {} on server {}.", channel.getId(), channel.getServer().getId());
|
||||
|
||||
@@ -11,6 +11,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@@ -43,6 +44,18 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
|
||||
removeAssignedRoleFromUser(assignableRole, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAssignedRoleFromUsers(AssignableRole assignableRole, List<AssignedRoleUser> users) {
|
||||
log.info("Clearing all assignable role {} for {} users.", assignableRole.getId(), users.size());
|
||||
assignableRole.getAssignedUsers().removeAll(users);
|
||||
users.forEach(roleUser -> roleUser.getRoles().remove(assignableRole));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAssignedRoleFromUsers(AssignableRole assignableRole) {
|
||||
removeAssignedRoleFromUsers(assignableRole, assignableRole.getAssignedUsers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAssignedRoleFromUser(AssignableRole assignableRole, AssignedRoleUser user) {
|
||||
assignableRole.getAssignedUsers().remove(user);
|
||||
|
||||
@@ -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="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?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-add_type">
|
||||
<addColumn tableName="assignable_role_place">
|
||||
<column name="type" type="VARCHAR2(128)" defaultValue="DEFAULT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="assignable_role_place.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -7,4 +7,5 @@
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="1.0-assignableRoles/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.3.4/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>assignable-roles-int</artifactId>
|
||||
|
||||
@@ -9,7 +9,7 @@ import net.dv8tion.jda.api.entities.Role;
|
||||
/**
|
||||
* Exception thrown in case the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRole} has already been
|
||||
* defined for an {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace}. This is identified
|
||||
* via the {@link net.dv8tion.jda.api.entities.Emote} which is used to react.
|
||||
* via the emote which is used to react.
|
||||
*/
|
||||
public class AssignableRoleAlreadyDefinedException extends AbstractoRunTimeException implements Templatable {
|
||||
private final AssignableRoleAlreadyDefinedExceptionModel model;
|
||||
|
||||
@@ -6,7 +6,7 @@ import dev.sheldan.abstracto.core.templating.Templatable;
|
||||
|
||||
/**
|
||||
* Exception thrown in case the {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace place}
|
||||
* identified by {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace#key}
|
||||
* identified by {@link dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace} key
|
||||
*/
|
||||
public class AssignableRolePlaceAlreadyExistsException extends AbstractoRunTimeException implements Templatable {
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.sheldan.abstracto.assignableroles.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
|
||||
|
||||
public class BoosterAssignableRolePlaceMemberNotBoostingException extends AbstractoTemplatableException {
|
||||
|
||||
public BoosterAssignableRolePlaceMemberNotBoostingException() {
|
||||
super("Clicking member does not boost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "assignable_role_booster_place_member_not_boosting_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
@@ -85,4 +85,8 @@ public class AssignableRolePlace implements Serializable {
|
||||
@Column(name = "updated", insertable = false, updatable = false)
|
||||
private Instant updated;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "type")
|
||||
private AssignableRolePlaceType type;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.assignableroles.model.database;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandParameterKey;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum AssignableRolePlaceType implements CommandParameterKey {
|
||||
DEFAULT, BOOSTER
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.abstracto.assignableroles.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.core.models.template.display.ChannelDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
@@ -19,6 +20,7 @@ public class AssignableRolePlaceConfig {
|
||||
private String placeText;
|
||||
private ChannelDisplay channelDisplay;
|
||||
private Boolean uniqueRoles;
|
||||
private AssignableRolePlaceType type;
|
||||
/**
|
||||
* The {@link AssignableRolePlaceConfig roles} which are contained in this {@link AssignableRolePlace}
|
||||
*/
|
||||
|
||||
@@ -2,17 +2,21 @@ package dev.sheldan.abstracto.assignableroles.service;
|
||||
|
||||
import dev.sheldan.abstracto.assignableroles.config.AssignableRolePlaceParameterKey;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.model.template.AssignablePlaceOverview;
|
||||
import dev.sheldan.abstracto.assignableroles.model.template.AssignableRolePlaceConfig;
|
||||
import dev.sheldan.abstracto.core.models.FullEmote;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.ARole;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface AssignableRolePlaceService {
|
||||
void createAssignableRolePlace(String name, AChannel channel, String text);
|
||||
void createAssignableRolePlace(String name, AChannel channel, String text, AssignableRolePlaceType type);
|
||||
|
||||
CompletableFuture<Void> addRoleToAssignableRolePlace(AServer server, String placeName, Role role, FullEmote emote, String description);
|
||||
|
||||
@@ -42,7 +46,7 @@ public interface AssignableRolePlaceService {
|
||||
|
||||
void multipleAssignableRolePlace(AssignableRolePlace place);
|
||||
|
||||
CompletableFuture<Void> showAssignablePlaceConfig(AServer server, String name, TextChannel channel);
|
||||
AssignableRolePlaceConfig getAssignableRolePlaceConfig(Guild guild, String name);
|
||||
|
||||
CompletableFuture<Void> moveAssignableRolePlace(AServer server, String name, TextChannel newChannel);
|
||||
|
||||
@@ -52,5 +56,5 @@ public interface AssignableRolePlaceService {
|
||||
|
||||
CompletableFuture<Void> changeConfiguration(AServer server, String name, AssignableRolePlaceParameterKey keyToChange, String newValue);
|
||||
|
||||
CompletableFuture<Void> showAllAssignableRolePlaces(AServer server, TextChannel channel);
|
||||
AssignablePlaceOverview getAssignableRolePlaceOverview(Guild guild);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ 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.assignableroles.model.database.AssignedRoleUser;
|
||||
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.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
@@ -22,6 +24,8 @@ public interface AssignableRoleService {
|
||||
*/
|
||||
|
||||
CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member member);
|
||||
CompletableFuture<Void> assignAssignableRoleToUser(Role role, Member member);
|
||||
void assignableRoleConditionFailure();
|
||||
|
||||
/**
|
||||
* Clears all {@link AssignableRole assignableRoles} which are currently given to the {@link AUserInAServer user} of a certain
|
||||
@@ -39,6 +43,7 @@ public interface AssignableRoleService {
|
||||
* has been removed from the {@link Member member}
|
||||
*/
|
||||
CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, Member member);
|
||||
CompletableFuture<Void> removeAssignableRoleFromUser(Role role, Member member);
|
||||
|
||||
/**
|
||||
* Removes the {@link AssignableRole role} from the given {@link Member member}
|
||||
@@ -67,4 +72,6 @@ public interface AssignableRoleService {
|
||||
AssignableRole getAssignableRoleInPlace(AssignableRolePlace place, ARole role);
|
||||
AssignableRole getAssignableRoleInPlace(AssignableRolePlace place, Long roleId);
|
||||
|
||||
void removeAssignableRolesFromAssignableRoleUser(List<AssignableRole> roles, AssignedRoleUser roleUser);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,14 +2,19 @@ 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.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
|
||||
import dev.sheldan.abstracto.core.models.FullEmote;
|
||||
import dev.sheldan.abstracto.core.models.database.ComponentPayload;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AssignableRoleManagementService {
|
||||
AssignableRole addRoleToPlace(FullEmote emote, Role role, String description, AssignableRolePlace place, ComponentPayload componentPayload);
|
||||
|
||||
AssignableRole getByAssignableRoleId(Long assignableRoleId);
|
||||
void deleteAssignableRole(AssignableRole assignableRole);
|
||||
List<AssignableRole> getAssignableRolesFromAssignableUserWithPlaceType(AssignedRoleUser user, AssignableRolePlaceType type);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.abstracto.assignableroles.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlace;
|
||||
import dev.sheldan.abstracto.assignableroles.model.database.AssignableRolePlaceType;
|
||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
|
||||
@@ -9,7 +10,7 @@ import java.util.Optional;
|
||||
|
||||
public interface AssignableRolePlaceManagementService {
|
||||
|
||||
AssignableRolePlace createPlace(String name, AChannel channel, String text);
|
||||
AssignableRolePlace createPlace(String name, AChannel channel, String text, AssignableRolePlaceType type);
|
||||
|
||||
boolean doesPlaceExist(AServer server, String name);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import dev.sheldan.abstracto.assignableroles.model.database.AssignedRoleUser;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@@ -25,6 +26,8 @@ public interface AssignedRoleUserManagementService {
|
||||
* @param aUserInAServer The {@link AUserInAServer user} from whom the {@link AssignableRole role} should be removed
|
||||
*/
|
||||
void removeAssignedRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer);
|
||||
void removeAssignedRoleFromUsers(AssignableRole assignableRole, List<AssignedRoleUser> users);
|
||||
void removeAssignedRoleFromUsers(AssignableRole assignableRole);
|
||||
|
||||
/**
|
||||
* Removes the given {@link AssignableRole assignableFrom} from the given {@link AssignedRoleUser user}.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<?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>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command</artifactId>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>custom-command-impl</artifactId>
|
||||
|
||||
<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>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -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>
|
||||
@@ -0,0 +1,73 @@
|
||||
package dev.sheldan.abstracto.customcommand.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.CommandAlternative;
|
||||
import dev.sheldan.abstracto.core.command.execution.UnParsedCommandParameter;
|
||||
import dev.sheldan.abstracto.core.command.service.CommandRegistry;
|
||||
import dev.sheldan.abstracto.core.config.ListenerPriority;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.FeatureFlagService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.customcommand.config.CustomCommandFeatureConfig;
|
||||
import dev.sheldan.abstracto.customcommand.model.command.CustomCommandResponseModel;
|
||||
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
|
||||
import dev.sheldan.abstracto.customcommand.service.management.CustomCommandManagementService;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class CustomCommandAlternative implements CommandAlternative {
|
||||
|
||||
private static final String CUSTOM_COMMAND_RESPONSE = "custom_command_response";
|
||||
|
||||
@Autowired
|
||||
private CommandRegistry commandRegistry;
|
||||
|
||||
@Autowired
|
||||
private CustomCommandManagementService customCommandManagementService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private FeatureFlagService featureFlagService;
|
||||
|
||||
@Autowired
|
||||
private CustomCommandFeatureConfig customCommandFeatureConfig;
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(UnParsedCommandParameter parameter, Guild guild) {
|
||||
return featureFlagService.isFeatureEnabled(customCommandFeatureConfig, guild.getIdLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(UnParsedCommandParameter parameter, Message message) {
|
||||
String contentStripped = message.getContentRaw();
|
||||
List<String> parameters = Arrays.asList(contentStripped.split(" "));
|
||||
String commandName = commandRegistry.getCommandName(parameters.get(0), message.getGuild().getIdLong());
|
||||
Optional<CustomCommand> customCommandOptional = customCommandManagementService.getCustomCommandByName(commandName, message.getGuild().getIdLong());
|
||||
customCommandOptional.ifPresent(customCommand -> {
|
||||
CustomCommandResponseModel model = CustomCommandResponseModel
|
||||
.builder()
|
||||
.additionalText(customCommand.getAdditionalMessage())
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(CUSTOM_COMMAND_RESPONSE, model, message.getGuild().getIdLong());
|
||||
channelService.sendMessageToSendToChannel(messageToSend, message.getChannel());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Integer getPriority() {
|
||||
return ListenerPriority.MEDIUM;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.customcommand.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@PropertySource("classpath:custom-command-config.properties")
|
||||
public class CustomCommandConfig {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package dev.sheldan.abstracto.customcommand.repository;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface CustomCommandRepository extends JpaRepository<CustomCommand, Long> {
|
||||
Optional<CustomCommand> getByNameIgnoreCaseAndServer(String name, AServer server);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package dev.sheldan.abstracto.customcommand.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
|
||||
import dev.sheldan.abstracto.customcommand.repository.CustomCommandRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class CustomCommandManagementServiceBean implements CustomCommandManagementService {
|
||||
|
||||
@Autowired
|
||||
private CustomCommandRepository repository;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Override
|
||||
public Optional<CustomCommand> getCustomCommandByName(String name, Long serverId) {
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
return repository.getByNameIgnoreCaseAndServer(name, server);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
abstracto.featureFlags.customCommand.featureName=customCommand
|
||||
abstracto.featureFlags.customCommand.enabled=false
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,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>
|
||||
@@ -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="custom_command-feature-insertion">
|
||||
<insert tableName="feature">
|
||||
<column name="key" value="customCommand"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,51 @@
|
||||
<?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="custom_command-table">
|
||||
<createTable tableName="custom_command">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="custom_command_pkey"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="creator_user_in_server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="additional_message" type="VARCHAR(2048)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="NAME" type="VARCHAR(64)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
</createTable>
|
||||
<addUniqueConstraint columnNames="name"
|
||||
constraintName="uc_custom_command_name"
|
||||
disabled="false"
|
||||
tableName="custom_command"/>
|
||||
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="custom_command"
|
||||
constraintName="fk_custom_command_server" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="creator_user_in_server_id" baseTableName="custom_command"
|
||||
constraintName="fk_custom_command_creator" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS custom_command_update_trigger ON custom_command;
|
||||
CREATE TRIGGER custom_command_update_trigger BEFORE UPDATE ON custom_command FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS custom_command_insert_trigger ON custom_command;
|
||||
CREATE TRIGGER custom_command_insert_trigger BEFORE INSERT ON custom_command FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="custom_command.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns: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.4.0/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
<?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>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command</artifactId>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>custom-command-int</artifactId>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,13 @@
|
||||
package dev.sheldan.abstracto.customcommand.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CustomCommandFeatureConfig implements FeatureConfig {
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return CustomCommandFeatureDefinition.CUSTOM_COMMAND;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.abstracto.customcommand.config;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum CustomCommandFeatureDefinition implements FeatureDefinition {
|
||||
CUSTOM_COMMAND("customCommand");
|
||||
|
||||
private String key;
|
||||
|
||||
CustomCommandFeatureDefinition(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.customcommand.model.command;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class CustomCommandResponseModel {
|
||||
private String additionalText;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package dev.sheldan.abstracto.customcommand.model.database;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.*;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
@Table(name = "custom_command")
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
public class CustomCommand implements Serializable {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "additional_message")
|
||||
private String additionalMessage;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "server_id", nullable = false)
|
||||
private AServer server;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "creator_user_in_server_id", nullable = false)
|
||||
private AUserInAServer creator;
|
||||
|
||||
@Column(name = "created", nullable = false, insertable = false, updatable = false)
|
||||
private Instant created;
|
||||
|
||||
@Column(name = "updated", insertable = false, updatable = false)
|
||||
private Instant updated;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.customcommand.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.customcommand.model.database.CustomCommand;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CustomCommandManagementService {
|
||||
Optional<CustomCommand> getCustomCommandByName(String name, Long serverId);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>custom-command</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>custom-command-int</module>
|
||||
<module>custom-command-impl</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.core</groupId>
|
||||
<artifactId>core-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ActivityServiceBean implements ActivityService {
|
||||
List<CustomActivity> activities = activityManagementService.getAllActivities();
|
||||
if(!activities.isEmpty()) {
|
||||
CustomActivity chosen = activities.get(secureRandom.nextInt(activities.size()));
|
||||
log.info("Chosen {} activity.", chosen.getId());
|
||||
log.info("Chosen activity {}.", chosen.getId());
|
||||
switchToActivity(chosen);
|
||||
} else {
|
||||
log.info("No activities configured.");
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.3.2</version>
|
||||
<version>1.4.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,16 +4,20 @@ 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.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.ChooseResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -25,30 +29,81 @@ import java.util.concurrent.CompletableFuture;
|
||||
public class Choose extends AbstractConditionableCommand {
|
||||
|
||||
public static final String CHOOSE_RESPONSE_TEMPLATE_KEY = "choose_response";
|
||||
private static final String CHOOSE_COMMAND = "choose";
|
||||
private static final String TEXT_PARAMETER = "text";
|
||||
private static final int CHOICES_SIZE = 5;
|
||||
|
||||
@Autowired
|
||||
private EntertainmentService entertainmentService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<String> choices = (List) commandContext.getParameters().getParameters().get(0);
|
||||
String choice = entertainmentService.takeChoice(choices, commandContext.getAuthor());
|
||||
ChooseResponseModel responseModel = (ChooseResponseModel) ContextConverter.slimFromCommandContext(commandContext, ChooseResponseModel.class);
|
||||
responseModel.setChosenValue(choice);
|
||||
ChooseResponseModel responseModel = ChooseResponseModel
|
||||
.builder()
|
||||
.chosenValue(choice)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(CHOOSE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
List<String> choices = new ArrayList<>();
|
||||
for (int i = 0; i < CHOICES_SIZE; i++) {
|
||||
if(slashCommandParameterService.hasCommandOption(TEXT_PARAMETER + "_" + i, event)) {
|
||||
String choice = slashCommandParameterService.getCommandOption(TEXT_PARAMETER + "_" + i, event, String.class);
|
||||
choices.add(choice);
|
||||
}
|
||||
}
|
||||
String choice = entertainmentService.takeChoice(choices, event.getMember());
|
||||
ChooseResponseModel responseModel = ChooseResponseModel
|
||||
.builder()
|
||||
.chosenValue(choice)
|
||||
.build();
|
||||
return interactionService.replyEmbed(CHOOSE_RESPONSE_TEMPLATE_KEY, responseModel, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(Parameter.builder().name("text").type(String.class).templated(true).remainder(true).isListParam(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
Parameter textParameter = Parameter
|
||||
.builder()
|
||||
.name(TEXT_PARAMETER)
|
||||
.type(String.class)
|
||||
.templated(true)
|
||||
.remainder(true)
|
||||
.listSize(CHOICES_SIZE)
|
||||
.isListParam(true)
|
||||
.build();
|
||||
parameters.add(textParameter);
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
|
||||
.commandName(CHOOSE_COMMAND)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name("choose")
|
||||
.name(CHOOSE_COMMAND)
|
||||
.async(true)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -4,17 +4,22 @@ 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.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.EightBallResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -26,6 +31,8 @@ import java.util.concurrent.CompletableFuture;
|
||||
public class EightBall extends AbstractConditionableCommand {
|
||||
|
||||
public static final String EIGHT_BALL_RESPONSE_TEMPLATE_KEY = "eight_ball_response";
|
||||
public static final String BALL_COMMAND = "8Ball";
|
||||
public static final String TEXT_PARAMETER = "text";
|
||||
@Autowired
|
||||
private EntertainmentService entertainmentService;
|
||||
|
||||
@@ -35,24 +42,65 @@ public class EightBall extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
String text = (String) commandContext.getParameters().getParameters().get(0);
|
||||
String chosenKey = entertainmentService.getEightBallValue(text);
|
||||
EightBallResponseModel responseModel = (EightBallResponseModel) ContextConverter.slimFromCommandContext(commandContext, EightBallResponseModel.class);
|
||||
responseModel.setChosenKey(chosenKey);
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(EIGHT_BALL_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
|
||||
MessageToSend messageToSend = getMessageToSend(text, commandContext.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
String text = slashCommandParameterService.getCommandOption(TEXT_PARAMETER, event, String.class);
|
||||
MessageToSend messageToSend = getMessageToSend(text, event.getGuild().getIdLong());
|
||||
return interactionService.replyMessageToSend(messageToSend, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
private MessageToSend getMessageToSend(String text, Long serverId) {
|
||||
String chosenKey = entertainmentService.getEightBallValue(text);
|
||||
EightBallResponseModel responseModel = EightBallResponseModel
|
||||
.builder()
|
||||
.chosenKey(chosenKey)
|
||||
.build();
|
||||
return templateService.renderEmbedTemplate(EIGHT_BALL_RESPONSE_TEMPLATE_KEY, responseModel, serverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(Parameter.builder().name("text").type(String.class).templated(true).remainder(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
Parameter textParameter = Parameter
|
||||
.builder()
|
||||
.name(TEXT_PARAMETER)
|
||||
.type(String.class)
|
||||
.templated(true)
|
||||
.remainder(true)
|
||||
.build();
|
||||
parameters.add(textParameter);
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
|
||||
.commandName(BALL_COMMAND)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name("8Ball")
|
||||
.name(BALL_COMMAND)
|
||||
.async(true)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -4,16 +4,22 @@ 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.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
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.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.LoveCalcResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -25,6 +31,9 @@ import java.util.concurrent.CompletableFuture;
|
||||
public class LoveCalc extends AbstractConditionableCommand {
|
||||
|
||||
public static final String LOVE_CALC_RESPONSE_TEMPLATE_KEY = "loveCalc_response";
|
||||
public static final String FIRST_SUBJECT_PARAMETER = "firstSubject";
|
||||
public static final String SECOND_SUBJECT_PARAMETER = "secondSubject";
|
||||
public static final String LOVE_CALC_COMMAND = "loveCalc";
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
@@ -32,28 +41,77 @@ public class LoveCalc extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private EntertainmentService entertainmentService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
String firstPart = (String) parameters.get(0);
|
||||
String secondPart = (String) parameters.get(1);
|
||||
Integer rolled = entertainmentService.getLoveCalcValue(firstPart, secondPart);
|
||||
LoveCalcResponseModel model = (LoveCalcResponseModel) ContextConverter.slimFromCommandContext(commandContext, LoveCalcResponseModel.class);
|
||||
model.setRolled(rolled);
|
||||
model.setFirstPart(firstPart);
|
||||
model.setSecondPart(secondPart);
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(LOVE_CALC_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
MessageToSend messageToSend = getMessageToSend(commandContext.getGuild().getIdLong(), firstPart, secondPart);
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
String firstPart = slashCommandParameterService.getCommandOption(FIRST_SUBJECT_PARAMETER, event, String.class);
|
||||
String secondPart = slashCommandParameterService.getCommandOption(SECOND_SUBJECT_PARAMETER, event, String.class);
|
||||
MessageToSend messageToSend = getMessageToSend(event.getGuild().getIdLong(), firstPart, secondPart);
|
||||
return interactionService.replyMessageToSend(messageToSend, event.getInteraction())
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
private MessageToSend getMessageToSend(Long serverId, String firstPart, String secondPart) {
|
||||
Integer rolled = entertainmentService.getLoveCalcValue(firstPart, secondPart);
|
||||
LoveCalcResponseModel model = LoveCalcResponseModel
|
||||
.builder()
|
||||
.rolled(rolled)
|
||||
.firstPart(firstPart)
|
||||
.secondPart(secondPart)
|
||||
.build();
|
||||
return templateService.renderEmbedTemplate(LOVE_CALC_RESPONSE_TEMPLATE_KEY, model, serverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(Parameter.builder().name("firstSubject").type(String.class).templated(true).build());
|
||||
parameters.add(Parameter.builder().name("secondSubject").type(String.class).templated(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
Parameter firstSubjectParameter = Parameter
|
||||
.builder()
|
||||
.name(FIRST_SUBJECT_PARAMETER)
|
||||
.type(String.class)
|
||||
.templated(true)
|
||||
.build();
|
||||
parameters.add(firstSubjectParameter);
|
||||
Parameter secondSubjectParameter = Parameter
|
||||
.builder()
|
||||
.name(SECOND_SUBJECT_PARAMETER)
|
||||
.type(String.class)
|
||||
.templated(true)
|
||||
.build();
|
||||
parameters.add(secondSubjectParameter);
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
|
||||
.commandName(LOVE_CALC_COMMAND)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name("loveCalc")
|
||||
.name(LOVE_CALC_COMMAND)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.async(true)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
|
||||
@@ -6,17 +6,21 @@ 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.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.command.handler.parameter.CombinedParameter;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.MockResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -29,12 +33,20 @@ import static dev.sheldan.abstracto.core.command.config.Parameter.ADDITIONAL_TYP
|
||||
public class Mock extends AbstractConditionableCommand {
|
||||
|
||||
public static final String MOCK_RESPONSE_TEMPLATE_KEY = "mock_response";
|
||||
public static final String MOCK_COMMAND = "mock";
|
||||
public static final String MESSAGE_PARAMETER = "message";
|
||||
@Autowired
|
||||
private EntertainmentService entertainmentService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
Object givenParameter = commandContext.getParameters().getParameters().get(0);
|
||||
@@ -48,26 +60,63 @@ public class Mock extends AbstractConditionableCommand {
|
||||
messageText = givenParameter.toString();
|
||||
}
|
||||
String mockingText = entertainmentService.createMockText(messageText, commandContext.getAuthor(), mockedMember);
|
||||
MockResponseModel model = (MockResponseModel) ContextConverter.slimFromCommandContext(commandContext, MockResponseModel.class);
|
||||
model.setOriginalText(messageText);
|
||||
model.setMockingText(mockingText);
|
||||
MockResponseModel model = MockResponseModel
|
||||
.builder()
|
||||
.originalText(messageText)
|
||||
.mockingText(mockingText)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(MOCK_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
String text = slashCommandParameterService.getCommandOption(MESSAGE_PARAMETER, event, String.class);
|
||||
String mockingText = entertainmentService.createMockText(text, event.getMember(), null);
|
||||
MockResponseModel model = MockResponseModel
|
||||
.builder()
|
||||
.originalText(text)
|
||||
.mockingText(mockingText)
|
||||
.build();
|
||||
return interactionService.replyEmbed(MOCK_RESPONSE_TEMPLATE_KEY, model, event.getInteraction())
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
Map<String, Object> parameterAlternatives = new HashMap<>();
|
||||
parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(Message.class, String.class));
|
||||
parameters.add(Parameter.builder().name("message").type(CombinedParameter.class).remainder(true)
|
||||
.additionalInfo(parameterAlternatives).templated(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
|
||||
Parameter messageParameter = Parameter
|
||||
.builder()
|
||||
.name(MESSAGE_PARAMETER)
|
||||
.type(CombinedParameter.class)
|
||||
.remainder(true)
|
||||
.additionalInfo(parameterAlternatives)
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
parameters.add(messageParameter);
|
||||
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.ENTERTAINMENT)
|
||||
.commandName(MOCK_COMMAND)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name("mock")
|
||||
.name(MOCK_COMMAND)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
|
||||
@@ -4,19 +4,23 @@ 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.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.RollResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -29,6 +33,9 @@ import java.util.concurrent.CompletableFuture;
|
||||
public class Roll extends AbstractConditionableCommand {
|
||||
|
||||
public static final String ROLL_RESPONSE_TEMPLATE_KEY = "roll_response";
|
||||
private static final String ROLL_COMMAND = "roll";
|
||||
private static final String LOW_PARAMETER = "low";
|
||||
private static final String HIGH_PARAMETER = "high";
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
@@ -39,6 +46,12 @@ public class Roll extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
@@ -52,20 +65,73 @@ public class Roll extends AbstractConditionableCommand {
|
||||
}
|
||||
|
||||
Integer rolled = entertainmentService.calculateRollResult(low, high);
|
||||
RollResponseModel model = (RollResponseModel) ContextConverter.slimFromCommandContext(commandContext, RollResponseModel.class);
|
||||
model.setRolled(rolled);
|
||||
RollResponseModel model = RollResponseModel
|
||||
.builder()
|
||||
.rolled(rolled)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ROLL_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
Integer low;
|
||||
if(slashCommandParameterService.hasCommandOption(LOW_PARAMETER, event)) {
|
||||
low = slashCommandParameterService.getCommandOption(LOW_PARAMETER, event, Integer.class);
|
||||
} else {
|
||||
low = 1;
|
||||
}
|
||||
Integer high;
|
||||
if(slashCommandParameterService.hasCommandOption(HIGH_PARAMETER, event)) {
|
||||
high = slashCommandParameterService.getCommandOption(HIGH_PARAMETER, event, Integer.class);
|
||||
} else {
|
||||
high = configService.getLongValueOrConfigDefault(EntertainmentFeatureConfig.ROLL_DEFAULT_HIGH_KEY, event.getGuild().getIdLong()).intValue();
|
||||
}
|
||||
Integer rolled = entertainmentService.calculateRollResult(low, high);
|
||||
RollResponseModel model = RollResponseModel
|
||||
.builder()
|
||||
.rolled(rolled)
|
||||
.build();
|
||||
return interactionService.replyEmbed(ROLL_RESPONSE_TEMPLATE_KEY, model, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
parameters.add(Parameter.builder().name("high").type(Integer.class).templated(true).validators(Arrays.asList(MinIntegerValueValidator.min(2L))).optional(true).build());
|
||||
parameters.add(Parameter.builder().name("low").type(Integer.class).templated(true).validators(Arrays.asList(MinIntegerValueValidator.min(0L))).optional(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
Parameter highParameter = Parameter
|
||||
.builder()
|
||||
.name(HIGH_PARAMETER)
|
||||
.type(Integer.class)
|
||||
.templated(true)
|
||||
.validators(Arrays.asList(MinIntegerValueValidator.min(2L)))
|
||||
.optional(true)
|
||||
.build();
|
||||
parameters.add(highParameter);
|
||||
Parameter lowParameter = Parameter
|
||||
.builder()
|
||||
.name(LOW_PARAMETER)
|
||||
.type(Integer.class)
|
||||
.templated(true)
|
||||
.validators(Arrays.asList(MinIntegerValueValidator.min(0L)))
|
||||
.optional(true)
|
||||
.build();
|
||||
parameters.add(lowParameter);
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
|
||||
.commandName(ROLL_COMMAND)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name("roll")
|
||||
.name(ROLL_COMMAND)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.async(true)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
|
||||
@@ -4,16 +4,19 @@ 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.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.RouletteResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -25,28 +28,57 @@ import java.util.concurrent.CompletableFuture;
|
||||
public class Roulette extends AbstractConditionableCommand {
|
||||
|
||||
public static final String ROULETTE_RESPONSE_TEMPLATE_KEY = "roulette_response";
|
||||
public static final String ROULETTE_COMMAND = "roulette";
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private EntertainmentService entertainmentService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
boolean rouletteResult = entertainmentService.executeRoulette(commandContext.getAuthor());
|
||||
RouletteResponseModel responseModel = (RouletteResponseModel) ContextConverter.slimFromCommandContext(commandContext, RouletteResponseModel.class);
|
||||
responseModel.setResult(rouletteResult);
|
||||
RouletteResponseModel responseModel = RouletteResponseModel
|
||||
.builder()
|
||||
.result(rouletteResult)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ROULETTE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromIgnored());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
boolean rouletteResult = entertainmentService.executeRoulette(event.getMember());
|
||||
RouletteResponseModel responseModel = RouletteResponseModel
|
||||
.builder()
|
||||
.result(rouletteResult)
|
||||
.build();
|
||||
return interactionService.replyEmbed(ROULETTE_RESPONSE_TEMPLATE_KEY, responseModel, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
|
||||
.commandName(ROULETTE_COMMAND)
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name("roulette")
|
||||
.name(ROULETTE_COMMAND)
|
||||
.async(true)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package dev.sheldan.abstracto.entertainment.command.economy;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
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.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.dto.CreditGambleResult;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.CreditGambleResultModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EconomyService;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class CreditGamble extends AbstractConditionableCommand {
|
||||
private static final String CREDIT_GAMBLE_COMMAND = "creditGamble";
|
||||
private static final String CREDIT_GAMBLE_RESPONSE = "creditGamble_response";
|
||||
|
||||
@Autowired
|
||||
private EconomyService economyService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
|
||||
CreditGambleResult result = economyService.triggerCreditGamble(aUserInAServer);
|
||||
CreditGambleResultModel model = CreditGambleResultModel.fromCreditGambleResult(result);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(CREDIT_GAMBLE_RESPONSE, model, commandContext.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
|
||||
CreditGambleResult result = economyService.triggerCreditGamble(aUserInAServer);
|
||||
CreditGambleResultModel model = CreditGambleResultModel.fromCreditGambleResult(result);
|
||||
return interactionService.replyEmbed(CREDIT_GAMBLE_RESPONSE, model, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.ECONOMY)
|
||||
.commandName("creditgamble")
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(CREDIT_GAMBLE_COMMAND)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.async(true)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.ECONOMY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package dev.sheldan.abstracto.entertainment.command.economy;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.MemberService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
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.CompletableFutureList;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.CreditsLeaderboardEntry;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.CreditsLeaderboardResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EconomyService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class CreditLeaderboard extends AbstractConditionableCommand {
|
||||
|
||||
private static final String CREDIT_LEADERBOARD_COMMAND_NAME = "creditLeaderboard";
|
||||
private static final String CREDIT_LEADERBOARD_RESPONSE = "creditLeaderboard_response";
|
||||
private static final String PAGE_PARAMETER = "page";
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private EconomyService economyService;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
AServer server = serverManagementService.loadServer(commandContext.getGuild());
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
// parameter is optional, in case its not present, we default to the 0th page
|
||||
Integer page = !parameters.isEmpty() ? (Integer) parameters.get(0) : 1;
|
||||
List<CreditsLeaderboardEntry> creditLeaderboard = economyService.getCreditLeaderboard(server, page);
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
|
||||
CreditsLeaderboardEntry ownRank = economyService.getRankOfUser(aUserInAServer);
|
||||
CreditsLeaderboardResponseModel model = CreditsLeaderboardResponseModel
|
||||
.builder()
|
||||
.entries(creditLeaderboard)
|
||||
.ownRank(ownRank)
|
||||
.build();
|
||||
return enrichModelWithMembers(model, commandContext.getGuild().getIdLong())
|
||||
.thenCompose(model1 -> {
|
||||
MessageToSend message = templateService.renderEmbedTemplate(CREDIT_LEADERBOARD_RESPONSE, model1, commandContext.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(message, commandContext.getChannel()));
|
||||
})
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
event.deferReply().queue();
|
||||
Integer page;
|
||||
if(slashCommandParameterService.hasCommandOption(PAGE_PARAMETER, event)) {
|
||||
page = slashCommandParameterService.getCommandOption(PAGE_PARAMETER, event, Integer.class);
|
||||
} else {
|
||||
page = 1;
|
||||
}
|
||||
AServer server = serverManagementService.loadServer(event.getGuild());
|
||||
List<CreditsLeaderboardEntry> creditLeaderboard = economyService.getCreditLeaderboard(server, page);
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
|
||||
CreditsLeaderboardEntry ownRank = economyService.getRankOfUser(aUserInAServer);
|
||||
CreditsLeaderboardResponseModel model = CreditsLeaderboardResponseModel
|
||||
.builder()
|
||||
.entries(creditLeaderboard)
|
||||
.ownRank(ownRank)
|
||||
.build();
|
||||
return enrichModelWithMembers(model, event.getGuild().getIdLong())
|
||||
.thenCompose(model1 -> FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(CREDIT_LEADERBOARD_RESPONSE, model1, event.getHook())))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
private CompletableFuture<CreditsLeaderboardResponseModel> enrichModelWithMembers(CreditsLeaderboardResponseModel model, Long serverId) {
|
||||
List<CompletableFuture<Member>> memberFutures = new ArrayList<>();
|
||||
model.getEntries().forEach(creditsLeaderboardEntry -> {
|
||||
memberFutures.add(memberService.getMemberInServerAsync(serverId, creditsLeaderboardEntry.getMemberDisplay().getUserId()));
|
||||
});
|
||||
memberFutures.add(memberService.getMemberInServerAsync(serverId, model.getOwnRank().getMemberDisplay().getUserId()));
|
||||
CompletableFuture<CreditsLeaderboardResponseModel> modelFuture = new CompletableFuture<>();
|
||||
CompletableFutureList<Member> futureList = new CompletableFutureList<>(memberFutures);
|
||||
futureList.getMainFuture().whenComplete((unused, throwable) -> {
|
||||
Map<Long, Member> memberMap = new HashMap<>();
|
||||
futureList.getObjects().forEach(member -> memberMap.put(member.getIdLong(), member));
|
||||
model.getEntries().forEach(creditsLeaderboardEntry -> {
|
||||
if(memberMap.containsKey(creditsLeaderboardEntry.getMemberDisplay().getUserId())) {
|
||||
creditsLeaderboardEntry.setMember(memberMap.get(creditsLeaderboardEntry.getMemberDisplay().getUserId()));
|
||||
}
|
||||
});
|
||||
if(memberMap.containsKey(model.getOwnRank().getMemberDisplay().getUserId())) {
|
||||
model.getOwnRank().setMember(memberMap.get(model.getOwnRank().getMemberDisplay().getUserId()));
|
||||
}
|
||||
modelFuture.complete(model);
|
||||
});
|
||||
return modelFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
Parameter pageParameter = Parameter
|
||||
.builder()
|
||||
.name(PAGE_PARAMETER)
|
||||
.optional(true)
|
||||
.templated(true)
|
||||
.type(Integer.class)
|
||||
.build();
|
||||
List<Parameter> parameters = Arrays.asList(pageParameter);
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.ECONOMY)
|
||||
.commandName("creditboard")
|
||||
.build();
|
||||
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(CREDIT_LEADERBOARD_COMMAND_NAME)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(false)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.ECONOMY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package dev.sheldan.abstracto.entertainment.command.economy;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
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.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.CreditsLeaderboardEntry;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.CreditsModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EconomyService;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class Credits extends AbstractConditionableCommand {
|
||||
|
||||
private static final String CREDITS_COMMAND = "credits";
|
||||
private static final String CREDITS_RESPONSE = "credits_response";
|
||||
|
||||
@Autowired
|
||||
private EconomyService economyService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
AUserInAServer targetUser = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
|
||||
CreditsLeaderboardEntry rankEntry = economyService.getRankOfUser(targetUser);
|
||||
rankEntry.setMember(commandContext.getAuthor());
|
||||
CreditsModel model = CreditsModel
|
||||
.builder()
|
||||
.entry(rankEntry)
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(CREDITS_RESPONSE, model, commandContext.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
AUserInAServer targetUser = userInServerManagementService.loadOrCreateUser(event.getMember());
|
||||
CreditsLeaderboardEntry rankEntry = economyService.getRankOfUser(targetUser);
|
||||
rankEntry.setMember(event.getMember());
|
||||
CreditsModel model = CreditsModel
|
||||
.builder()
|
||||
.entry(rankEntry)
|
||||
.build();
|
||||
return interactionService.replyEmbed(CREDITS_RESPONSE, model, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.ECONOMY)
|
||||
.commandName("credits")
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(CREDITS_COMMAND)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.async(true)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.ECONOMY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package dev.sheldan.abstracto.entertainment.command.economy;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
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.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.dto.PayDayResult;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.PayDayResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyLeaderboardResult;
|
||||
import dev.sheldan.abstracto.entertainment.service.EconomyService;
|
||||
import dev.sheldan.abstracto.entertainment.service.management.EconomyUserManagementService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class Payday extends AbstractConditionableCommand {
|
||||
|
||||
private static final String PAYDAY_COMMAND_NAME = "payday";
|
||||
|
||||
@Autowired
|
||||
private EconomyService economyService;
|
||||
|
||||
@Autowired
|
||||
private EconomyUserManagementService economyUserManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
private static final String PAYDAY_RESPONSE = "payday_response";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
Member member = commandContext.getAuthor();
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
PayDayResult payDayResult = economyService.triggerPayDay(aUserInAServer);
|
||||
EconomyLeaderboardResult rank = economyUserManagementService.getRankOfUserInServer(aUserInAServer);
|
||||
PayDayResponseModel responseModel = PayDayResponseModel
|
||||
.builder()
|
||||
.currentCredits(payDayResult.getCurrentCredits())
|
||||
.gainedCredits(payDayResult.getGainedCredits())
|
||||
.leaderboardPosition(rank.getRank().longValue())
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PAYDAY_RESPONSE, responseModel, member.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
Member member = event.getMember();
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
PayDayResult payDayResult = economyService.triggerPayDay(aUserInAServer);
|
||||
EconomyLeaderboardResult rank = economyUserManagementService.getRankOfUserInServer(aUserInAServer);
|
||||
PayDayResponseModel responseModel = PayDayResponseModel
|
||||
.builder()
|
||||
.currentCredits(payDayResult.getCurrentCredits())
|
||||
.gainedCredits(payDayResult.getGainedCredits())
|
||||
.leaderboardPosition(rank.getRank().longValue())
|
||||
.build();
|
||||
return interactionService.replyEmbed(PAYDAY_RESPONSE, responseModel, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.ECONOMY)
|
||||
.commandName("payday")
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(PAYDAY_COMMAND_NAME)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.async(true)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.ECONOMY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package dev.sheldan.abstracto.entertainment.command.economy;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
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.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.dto.SlotsResult;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.SlotsResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EconomyServiceBean;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class Slots extends AbstractConditionableCommand {
|
||||
|
||||
private static final String SLOTS_COMMAND_NAME = "slots";
|
||||
private static final String BID_PARAMETER = "bid";
|
||||
private static final String SLOTS_RESPONSE = "slots_response";
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private EconomyServiceBean economyUserServiceBean;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
Integer bid = (Integer) commandContext.getParameters().getParameters().get(0);
|
||||
Member member = commandContext.getAuthor();
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
SlotsResult slotsResult = economyUserServiceBean.triggerSlots(aUserInAServer, bid.longValue());
|
||||
SlotsResponseModel responseModel = SlotsResponseModel.fromSlotsResult(slotsResult);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(SLOTS_RESPONSE, responseModel, member.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
Long bid = slashCommandParameterService.getCommandOption(BID_PARAMETER, event, Integer.class).longValue();
|
||||
Member member = event.getMember();
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
SlotsResult slotsResult = economyUserServiceBean.triggerSlots(aUserInAServer, bid);
|
||||
SlotsResponseModel responseModel = SlotsResponseModel.fromSlotsResult(slotsResult);
|
||||
return interactionService.replyEmbed(SLOTS_RESPONSE, responseModel, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
Parameter lowParameter = Parameter
|
||||
.builder()
|
||||
.name(BID_PARAMETER)
|
||||
.type(Integer.class)
|
||||
.templated(true)
|
||||
.validators(Arrays.asList(MinIntegerValueValidator.min(0L)))
|
||||
.build();
|
||||
parameters.add(lowParameter);
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.ECONOMY)
|
||||
.commandName("slots")
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(SLOTS_COMMAND_NAME)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.async(true)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.ECONOMY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package dev.sheldan.abstracto.entertainment.command.economy;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.TransferCreditsModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EconomyService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class TransferCredits extends AbstractConditionableCommand {
|
||||
private static final String TRANSFER_CREDITS_COMMAND = "transferCredits";
|
||||
private static final String TRANSFER_CREDITS_RESPONSE = "transferCredits_response";
|
||||
private static final String MEMBER_PARAMETER = "targetMember";
|
||||
private static final String AMOUNT_PARAMETER = "amount";
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private EconomyService economyService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Member targetMember = (Member) parameters.get(0);
|
||||
Integer amount = (Integer) parameters.get(1);
|
||||
AUserInAServer targetUser = userInServerManagementService.loadOrCreateUser(targetMember);
|
||||
AUserInAServer sourceUser = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
|
||||
economyService.transferCredits(sourceUser, targetUser, amount.longValue());
|
||||
TransferCreditsModel responseModel = TransferCreditsModel
|
||||
.builder()
|
||||
.sourceMember(MemberDisplay.fromMember(commandContext.getAuthor()))
|
||||
.targetMember(MemberDisplay.fromMember(targetMember))
|
||||
.credits(amount)
|
||||
.build();
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(TRANSFER_CREDITS_RESPONSE, responseModel, commandContext.getChannel()))
|
||||
.thenApply(unused -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
Member targetMember = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER, event, Member.class);
|
||||
Integer amount = slashCommandParameterService.getCommandOption(AMOUNT_PARAMETER, event, Integer.class);
|
||||
AUserInAServer targetUser = userInServerManagementService.loadOrCreateUser(targetMember);
|
||||
AUserInAServer sourceUser = userInServerManagementService.loadOrCreateUser(event.getMember());
|
||||
TransferCreditsModel responseModel = TransferCreditsModel
|
||||
.builder()
|
||||
.sourceMember(MemberDisplay.fromMember(event.getMember()))
|
||||
.targetMember(MemberDisplay.fromMember(targetMember))
|
||||
.credits(amount)
|
||||
.build();
|
||||
economyService.transferCredits(sourceUser, targetUser, amount.longValue());
|
||||
return interactionService.replyEmbed(TRANSFER_CREDITS_RESPONSE, responseModel, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
Parameter memberParameter = Parameter
|
||||
.builder()
|
||||
.name(MEMBER_PARAMETER)
|
||||
.templated(true)
|
||||
.type(Member.class)
|
||||
.optional(true)
|
||||
.build();
|
||||
|
||||
Parameter amountParameter = Parameter
|
||||
.builder()
|
||||
.name(AMOUNT_PARAMETER)
|
||||
.templated(true)
|
||||
.type(Integer.class)
|
||||
.optional(true)
|
||||
.build();
|
||||
|
||||
List<Parameter> parameters = Arrays.asList(memberParameter, amountParameter);
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(EntertainmentSlashCommandNames.ECONOMY)
|
||||
.commandName("transfer")
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(TRANSFER_CREDITS_COMMAND)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.module(EntertainmentModuleDefinition.ENTERTAINMENT)
|
||||
.templated(true)
|
||||
.supportsEmbedException(true)
|
||||
.parameters(parameters)
|
||||
.causesReaction(false)
|
||||
.async(true)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.ECONOMY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package dev.sheldan.abstracto.entertainment.listener.interaction;
|
||||
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.MessageContextConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.context.ContextCommandService;
|
||||
import dev.sheldan.abstracto.core.interaction.context.message.listener.MessageContextCommandListener;
|
||||
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
|
||||
import dev.sheldan.abstracto.core.models.listener.interaction.MessageContextInteractionModel;
|
||||
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.MockResponseModel;
|
||||
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import static dev.sheldan.abstracto.entertainment.command.Mock.MOCK_RESPONSE_TEMPLATE_KEY;
|
||||
|
||||
|
||||
@Component
|
||||
public class MockMessageContextCommandListener implements MessageContextCommandListener {
|
||||
|
||||
@Autowired
|
||||
private ContextCommandService contextCommandService;
|
||||
|
||||
@Autowired
|
||||
private EntertainmentService entertainmentService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MessageContextInteractionModel eventModel) {
|
||||
Message targetMessage = eventModel.getEvent().getTarget();
|
||||
String mockText = entertainmentService.createMockText(targetMessage.getContentRaw(), eventModel.getEvent().getMember(), targetMessage.getMember());
|
||||
MockResponseModel model = MockResponseModel
|
||||
.builder()
|
||||
.originalText(targetMessage.getContentRaw())
|
||||
.mockingText(mockText)
|
||||
.build();
|
||||
interactionService.replyEmbed(MOCK_RESPONSE_TEMPLATE_KEY, model, eventModel.getEvent());
|
||||
return DefaultListenerResult.PROCESSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return EntertainmentFeatureDefinition.ENTERTAINMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageContextConfig getConfig() {
|
||||
return MessageContextConfig
|
||||
.builder()
|
||||
.isTemplated(true)
|
||||
.name("mock")
|
||||
.templateKey("mock_message_context_menu_label")
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean handlesEvent(MessageContextInteractionModel model) {
|
||||
return contextCommandService.matchesGuildContextName(model, getConfig(), model.getServerId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package dev.sheldan.abstracto.entertainment.repository;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyLeaderboardResult;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyUser;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface EconomyUserRepository extends JpaRepository<EconomyUser, Long> {
|
||||
Optional<EconomyUser> findByUser(AUserInAServer aUserInAServer);
|
||||
|
||||
@Query(value = "WITH economy_user_ranked AS" +
|
||||
"( " +
|
||||
" SELECT eu.id, eu.credits, uis.user_id, ROW_NUMBER() OVER ( ORDER BY credits DESC ) " +
|
||||
" FROM economy_user eu INNER JOIN user_in_server uis ON eu.id = uis.user_in_server_id INNER JOIN server s ON s.id = uis.server_id WHERE s.id = :serverId" +
|
||||
") " +
|
||||
"SELECT rank.id as \"id\", rank.user_id as \"userid\", rank.credits as \"credits\", rank.row_number as \"rank\" " +
|
||||
"FROM economy_user_ranked rank " +
|
||||
"WHERE rank.id = :userInServerId", nativeQuery = true)
|
||||
EconomyLeaderboardResult getRankOfUserInServer(@Param("userInServerId") Long id, @Param("serverId") Long serverId);
|
||||
|
||||
@Query(value = "WITH economy_user_ranked AS" +
|
||||
"( " +
|
||||
" SELECT eu.id, eu.credits, uis.user_id, ROW_NUMBER() OVER ( ORDER BY credits DESC ) " +
|
||||
" FROM economy_user eu INNER JOIN user_in_server uis ON eu.id = uis.user_in_server_id INNER JOIN server s ON s.id = uis.server_id WHERE s.id = :serverId" +
|
||||
") " +
|
||||
"SELECT rank.id as \"id\", rank.user_id as \"userid\", rank.credits as \"credits\", rank.row_number as \"rank\" " +
|
||||
"FROM economy_user_ranked rank ", nativeQuery = true)
|
||||
List<EconomyLeaderboardResult> getRanksInServer(@Param("serverId") Long serverId);
|
||||
List<EconomyUser> findTop10ByServerOrderByCreditsDesc(AServer server, Pageable pageable);
|
||||
|
||||
List<EconomyUser> findByServerOrderByCredits(AServer server);
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
package dev.sheldan.abstracto.entertainment.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import dev.sheldan.abstracto.core.service.ConfigService;
|
||||
import dev.sheldan.abstracto.entertainment.config.EconomyFeatureConfig;
|
||||
import dev.sheldan.abstracto.entertainment.dto.CreditGambleResult;
|
||||
import dev.sheldan.abstracto.entertainment.dto.PayDayResult;
|
||||
import dev.sheldan.abstracto.entertainment.dto.SlotsResult;
|
||||
import dev.sheldan.abstracto.entertainment.exception.NotEnoughCreditsException;
|
||||
import dev.sheldan.abstracto.entertainment.exception.PayDayCooldownException;
|
||||
import dev.sheldan.abstracto.entertainment.exception.SlotsCooldownException;
|
||||
import dev.sheldan.abstracto.entertainment.model.command.CreditsLeaderboardEntry;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyLeaderboardResult;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyUser;
|
||||
import dev.sheldan.abstracto.entertainment.service.management.EconomyUserManagementService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
|
||||
import static dev.sheldan.abstracto.entertainment.config.EconomyFeatureConfig.PAYDAY_COOLDOWN_CONFIG_KEY;
|
||||
import static dev.sheldan.abstracto.entertainment.config.EconomyFeatureConfig.SLOTS_COOLDOWN_CONFIG_KEY;
|
||||
|
||||
@Component
|
||||
public class EconomyServiceBean implements EconomyService {
|
||||
|
||||
@Autowired
|
||||
private ConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private EconomyUserManagementService economyUserManagementService;
|
||||
|
||||
@Autowired
|
||||
private SecureRandom secureRandom;
|
||||
|
||||
private static final String CREDIT_GAMBLE_STORAGE = "creditGambleJackpot";
|
||||
|
||||
private static final String SNOWFLAKE = "❄";
|
||||
private static final String CHERRY = "🍒";
|
||||
private static final String COOKIE = "🍪";
|
||||
private static final String TWO = "2️⃣";
|
||||
private static final String CLOVER = "🍀";
|
||||
private static final String MUSHROOM = "🍄";
|
||||
private static final String SUNFLOWER = "🌻";
|
||||
private static final String HEART = "❤";
|
||||
private static final String SIX = "6️⃣";
|
||||
private static final String CYCLONE = "🌀";
|
||||
private static final String OUTCOME_KEY_THREE_CHERRIES = "threecherries";
|
||||
private static final String OUTCOME_KEY_NOTHING = "nothing";
|
||||
private static final String OUTCOME_KEY_JACKPOT = "jackpot";
|
||||
private static final String OUTCOME_KEY_CLOVERS = "clovers";
|
||||
private static final String OUTCOME_KEY_TWO_CHERRIES = "twocherries";
|
||||
private static final String OUTCOME_KEY_TWOSIX = "twosix";
|
||||
private static final String OUTCOME_KEY_3SYMBOLS = "threesymbols";
|
||||
private static final String OUTCOME_KEY_2SYMBOLS = "twosymbols";
|
||||
private static final List<String> POSSIBLE_SLOTS = Arrays.asList(SNOWFLAKE, CHERRY, COOKIE, TWO, CLOVER, MUSHROOM, SUNFLOWER, HEART, SIX, CYCLONE);
|
||||
private static final List<SlotMapping> WINNING_PATTERNS = Arrays.asList(
|
||||
new SlotMapping(Arrays.asList(CHERRY, CHERRY, CHERRY), 20, OUTCOME_KEY_THREE_CHERRIES),
|
||||
new SlotMapping(Arrays.asList(CLOVER, CLOVER, CLOVER), 25, OUTCOME_KEY_CLOVERS),
|
||||
new SlotMapping(Arrays.asList(TWO, TWO, SIX), 50, OUTCOME_KEY_JACKPOT),
|
||||
new SlotMapping(Arrays.asList(TWO, SIX), 4, OUTCOME_KEY_TWOSIX),
|
||||
new SlotMapping(Arrays.asList(CHERRY, CHERRY), 3, OUTCOME_KEY_TWO_CHERRIES)
|
||||
);
|
||||
private static final Integer TRIPLE_FACTOR = 10;
|
||||
private static final Integer DOUBLE_FACTOR = 2;
|
||||
|
||||
@Override
|
||||
public boolean canTriggerPayDay(AUserInAServer aUserInAServer) {
|
||||
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(aUserInAServer);
|
||||
return userOptional.map(this::canTriggerPayDay).orElse(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTriggerSlots(AUserInAServer aUserInAServer) {
|
||||
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(aUserInAServer);
|
||||
return userOptional.map(this::canTriggerSlots).orElse(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTriggerPayDay(EconomyUser economyUser) {
|
||||
return slotsTriggerIn(economyUser).isNegative();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTriggerSlots(EconomyUser economyUser) {
|
||||
return payDayTriggerIn(economyUser).isNegative();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration payDayTriggerIn(EconomyUser economyUser) {
|
||||
Long cooldownSeconds = configService.getLongValueOrConfigDefault(PAYDAY_COOLDOWN_CONFIG_KEY, economyUser.getServer().getId());
|
||||
Instant minTimeStamp = Instant.now().minus(cooldownSeconds, ChronoUnit.SECONDS);
|
||||
return Duration.between(economyUser.getLastPayDay(), minTimeStamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration slotsTriggerIn(EconomyUser economyUser) {
|
||||
Long cooldownSeconds = configService.getLongValueOrConfigDefault(SLOTS_COOLDOWN_CONFIG_KEY, economyUser.getServer().getId());
|
||||
Instant minTimeStamp = Instant.now().minus(cooldownSeconds, ChronoUnit.SECONDS);
|
||||
return Duration.between(economyUser.getLastSlots(), minTimeStamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EconomyUser addCredits(AUserInAServer aUserInAServer, Long credits) {
|
||||
Optional<EconomyUser> existingUserOptional = economyUserManagementService.getUser(aUserInAServer);
|
||||
if (existingUserOptional.isPresent()) {
|
||||
EconomyUser existingUser = existingUserOptional.get();
|
||||
addCredits(existingUser, credits);
|
||||
return existingUser;
|
||||
} else {
|
||||
EconomyUser user = economyUserManagementService.createUser(aUserInAServer);
|
||||
user.setCredits(credits);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCredits(EconomyUser economyUser, Long credits) {
|
||||
economyUser.setCredits(economyUser.getCredits() + credits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPayDayCredits(AUserInAServer aUserInAServer) {
|
||||
Long creditsToAdd = configService.getLongValueOrConfigDefault(EconomyFeatureConfig.PAYDAY_CREDITS_CONFIG_KEY,
|
||||
aUserInAServer.getServerReference().getId());
|
||||
addCredits(aUserInAServer, creditsToAdd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayDayResult triggerPayDay(AUserInAServer aUserInAServer) {
|
||||
Long creditsToAdd = configService.getLongValueOrConfigDefault(EconomyFeatureConfig.PAYDAY_CREDITS_CONFIG_KEY,
|
||||
aUserInAServer.getServerReference().getId());
|
||||
EconomyUser economyUser = addCredits(aUserInAServer, creditsToAdd);
|
||||
Duration durationForPayday = payDayTriggerIn(economyUser);
|
||||
if (durationForPayday.isNegative()) {
|
||||
throw new PayDayCooldownException(durationForPayday.abs());
|
||||
}
|
||||
economyUser.setLastPayDay(Instant.now());
|
||||
return PayDayResult
|
||||
.builder()
|
||||
.currentCredits(economyUser.getCredits())
|
||||
.gainedCredits(creditsToAdd)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotsResult triggerSlots(AUserInAServer aUserInAServer, Long bid) {
|
||||
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(aUserInAServer);
|
||||
if(!userOptional.isPresent()) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
EconomyUser user = userOptional.get();
|
||||
Long oldCredits = user.getCredits();
|
||||
if(user.getCredits() < bid) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
Duration durationForSlots = slotsTriggerIn(user);
|
||||
if (durationForSlots.isNegative()) {
|
||||
throw new SlotsCooldownException(durationForSlots.abs());
|
||||
}
|
||||
SlotGame slotGame = playSlots();
|
||||
Integer factor = slotGame.getResultFactor();
|
||||
Long creditChange = bid * factor;
|
||||
addCredits(user, -bid);
|
||||
addCredits(user, creditChange);
|
||||
|
||||
user.setLastSlots(Instant.now());
|
||||
return SlotsResult
|
||||
.builder()
|
||||
.bid(bid)
|
||||
.factor(factor.longValue())
|
||||
.newCredits(user.getCredits())
|
||||
.outComeKey(slotGame.getOutcome())
|
||||
.oldCredits(oldCredits)
|
||||
.winnings(creditChange)
|
||||
.rows(slotGame.getRows())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlotGame playSlots() {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
List<String> tempSlots = new ArrayList<>(POSSIBLE_SLOTS);
|
||||
Collections.rotate(tempSlots, secureRandom.nextInt(2000) - 1000);
|
||||
result.add(tempSlots.get(0));
|
||||
result.add(tempSlots.get(1));
|
||||
result.add(tempSlots.get(2));
|
||||
}
|
||||
List<List<String>> rows = new ArrayList<>();
|
||||
rows.add(Arrays.asList(result.get(0), result.get(3), result.get(6)));
|
||||
List<String> decidingRow = Arrays.asList(result.get(1), result.get(4), result.get(7));
|
||||
rows.add(decidingRow);
|
||||
rows.add(Arrays.asList(result.get(2), result.get(5), result.get(8)));
|
||||
String decidingRowAsString = String.join("", decidingRow);
|
||||
SlotMapping specialPattern = getSpecialPattern(decidingRowAsString);
|
||||
Integer factor = 0;
|
||||
String outcomeKey = OUTCOME_KEY_NOTHING;
|
||||
if(specialPattern != null){
|
||||
factor = specialPattern.factor;
|
||||
outcomeKey = specialPattern.outcome;
|
||||
} else {
|
||||
Set<String> uniqueChars = new HashSet<>(decidingRow);
|
||||
if(uniqueChars.size() == 1) {
|
||||
factor = TRIPLE_FACTOR;
|
||||
outcomeKey = OUTCOME_KEY_3SYMBOLS;
|
||||
} else if(decidingRow.get(0).equals(decidingRow.get(1)) || decidingRow.get(1).equals(decidingRow.get(2)) ) {
|
||||
factor = DOUBLE_FACTOR;
|
||||
outcomeKey = OUTCOME_KEY_2SYMBOLS;
|
||||
}
|
||||
}
|
||||
return SlotGame
|
||||
.builder()
|
||||
.rows(rows)
|
||||
.outcome(outcomeKey)
|
||||
.resultFactor(factor)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CreditsLeaderboardEntry> getCreditLeaderboard(AServer server, Integer page) {
|
||||
if(page <= 0) {
|
||||
throw new IllegalArgumentException("Page needs to be >= 1");
|
||||
}
|
||||
page--;
|
||||
int pageSize = 10;
|
||||
List<CreditsLeaderboardEntry> entries = new ArrayList<>();
|
||||
List<EconomyUser> ranks = economyUserManagementService.getRanksInServer(server, page, pageSize);
|
||||
int pageOffset = page * pageSize;
|
||||
for (int i = 0; i < ranks.size(); i++) {
|
||||
EconomyUser rank = ranks.get(i);
|
||||
CreditsLeaderboardEntry entry = CreditsLeaderboardEntry
|
||||
.builder()
|
||||
.credits(rank.getCredits())
|
||||
.memberDisplay(MemberDisplay.fromAUserInAServer(rank.getUser()))
|
||||
.rank(pageOffset + i + 1)
|
||||
.build();
|
||||
entries.add(entry);
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreditsLeaderboardEntry getRankOfUser(AUserInAServer aUserInAServer) {
|
||||
EconomyLeaderboardResult rank = economyUserManagementService.getRankOfUserInServer(aUserInAServer);
|
||||
if(rank != null) {
|
||||
return CreditsLeaderboardEntry
|
||||
.builder()
|
||||
.credits(rank.getCredits())
|
||||
.memberDisplay(MemberDisplay.fromAUserInAServer(aUserInAServer))
|
||||
.rank(rank.getRank())
|
||||
.build();
|
||||
} else {
|
||||
return CreditsLeaderboardEntry
|
||||
.builder()
|
||||
.credits(0L)
|
||||
.memberDisplay(MemberDisplay.fromAUserInAServer(aUserInAServer))
|
||||
.rank(-1)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferCredits(AUserInAServer source, AUserInAServer target, Long amount) {
|
||||
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(source);
|
||||
if(!userOptional.isPresent()) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
EconomyUser user = userOptional.get();
|
||||
if(user.getCredits() < amount) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
addCredits(target, amount);
|
||||
addCredits(user, -amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreditGambleResult triggerCreditGamble(AUserInAServer aUserInAServer) {
|
||||
// TODO move these constants to system configs
|
||||
Optional<EconomyUser> userOptional = economyUserManagementService.getUser(aUserInAServer);
|
||||
if(!userOptional.isPresent()) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
EconomyUser user = userOptional.get();
|
||||
Long bid = 25L;
|
||||
if(user.getCredits() < bid) {
|
||||
throw new NotEnoughCreditsException();
|
||||
}
|
||||
Long serverId = aUserInAServer.getServerReference().getId();
|
||||
Long currentJackpot = configService.getLongValueOrConfigDefault(CREDIT_GAMBLE_STORAGE, serverId);
|
||||
List<Integer> diceRoles = new ArrayList<>();
|
||||
diceRoles.add(creditGambleDiceResult());
|
||||
diceRoles.add(creditGambleDiceResult());
|
||||
diceRoles.add(creditGambleDiceResult());
|
||||
diceRoles.add(creditGambleDiceResult());
|
||||
|
||||
Long toJackpot = 20L;
|
||||
Integer uniqueNumbers = new HashSet<>(diceRoles).size();
|
||||
Boolean won = uniqueNumbers == 1;
|
||||
CreditGambleResult result = CreditGambleResult
|
||||
.builder()
|
||||
.uniqueNumbers(uniqueNumbers)
|
||||
.won(won)
|
||||
.bid(bid)
|
||||
.toBank(bid - toJackpot)
|
||||
.toJackpot(toJackpot)
|
||||
.rolls(diceRoles)
|
||||
.currentJackpot(currentJackpot + toJackpot)
|
||||
.build();
|
||||
if(won) {
|
||||
addCredits(user, currentJackpot);
|
||||
currentJackpot = 1000L;
|
||||
} else {
|
||||
currentJackpot += toJackpot;
|
||||
addCredits(user, -bid);
|
||||
}
|
||||
configService.setOrCreateConfigValue(CREDIT_GAMBLE_STORAGE, serverId, currentJackpot.toString());
|
||||
return result;
|
||||
}
|
||||
|
||||
private Integer creditGambleDiceResult() {
|
||||
return secureRandom.nextInt(7) + 1;
|
||||
}
|
||||
|
||||
private SlotMapping getSpecialPattern(String row){
|
||||
return WINNING_PATTERNS
|
||||
.stream()
|
||||
.filter(slotMapping -> row.contains(slotMapping.processedMapping))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static class SlotMapping {
|
||||
private Integer factor;
|
||||
private String processedMapping;
|
||||
private String outcome;
|
||||
|
||||
public SlotMapping(List<String> slots, Integer factor, String outcome) {
|
||||
this.factor = factor;
|
||||
this.processedMapping = String.join("", slots);
|
||||
this.outcome = outcome;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package dev.sheldan.abstracto.entertainment.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyLeaderboardResult;
|
||||
import dev.sheldan.abstracto.entertainment.model.database.EconomyUser;
|
||||
import dev.sheldan.abstracto.entertainment.repository.EconomyUserRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class EconomyUserManagementServiceBean implements EconomyUserManagementService {
|
||||
|
||||
@Autowired
|
||||
private EconomyUserRepository repository;
|
||||
|
||||
@Override
|
||||
public EconomyUser createUser(AUserInAServer aUserInAServer) {
|
||||
EconomyUser user = EconomyUser
|
||||
.builder()
|
||||
.id(aUserInAServer.getUserInServerId())
|
||||
.server(aUserInAServer.getServerReference())
|
||||
.lastPayDay(Instant.now().minus(1, ChronoUnit.DAYS))
|
||||
.lastSlots(Instant.now().minus(1, ChronoUnit.DAYS))
|
||||
.credits(0L)
|
||||
.user(aUserInAServer)
|
||||
.build();
|
||||
return repository.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<EconomyUser> getUser(AUserInAServer aUserInAServer) {
|
||||
return repository.findByUser(aUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EconomyLeaderboardResult getRankOfUserInServer(AUserInAServer aUserInAServer) {
|
||||
return repository.getRankOfUserInServer(aUserInAServer.getUserInServerId(), aUserInAServer.getServerReference().getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EconomyUser> getRanksInServer(AServer server, Integer page, Integer pagesize) {
|
||||
return repository.findTop10ByServerOrderByCreditsDesc(server, PageRequest.of(page, pagesize));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user