mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-01-01 23:35:29 +00:00
Compare commits
117 Commits
v1.5.25
...
release-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
feabe6426e | ||
|
|
2dc21ce996 | ||
|
|
5643a41fd8 | ||
|
|
08d0561998 | ||
|
|
879c1b0173 | ||
|
|
d5bf70f586 | ||
|
|
4525fbc861 | ||
|
|
4671a78ff9 | ||
|
|
c4174562c6 | ||
|
|
bfaa5d6140 | ||
|
|
d2e8398fa4 | ||
|
|
c67209925a | ||
|
|
f3ac7895eb | ||
|
|
6d893e39bb | ||
|
|
94140104de | ||
|
|
6d80423244 | ||
|
|
27040e506a | ||
|
|
3bbf5a2391 | ||
|
|
11cb3b9ee1 | ||
|
|
dccf314e53 | ||
|
|
a0daeee3a1 | ||
|
|
1b7c383ced | ||
|
|
087dd266cc | ||
|
|
beda17f672 | ||
|
|
5c234295aa | ||
|
|
9cfe4bf353 | ||
|
|
75c45541c9 | ||
|
|
11ac33ad4a | ||
|
|
a37a0f87a0 | ||
|
|
69353d32db | ||
|
|
b973c4660c | ||
|
|
34692d22eb | ||
|
|
33268cded6 | ||
|
|
40d66df9b0 | ||
|
|
92508d7a1d | ||
|
|
ccbf6147e9 | ||
|
|
a3545c4af0 | ||
|
|
fa187f8817 | ||
|
|
c39b7ebeec | ||
|
|
5cbad801ff | ||
|
|
826bee1f81 | ||
|
|
99bf9a9be0 | ||
|
|
5b5e4973a7 | ||
|
|
65e956827c | ||
|
|
b258a8bc54 | ||
|
|
9864b7d875 | ||
|
|
27466b7333 | ||
|
|
bfb8969d1f | ||
|
|
0097ff801a | ||
|
|
b6a188c04d | ||
|
|
2fa1adde02 | ||
|
|
cb8b64cc01 | ||
|
|
3b3dd0dbb7 | ||
|
|
388fead2a6 | ||
|
|
336c3d0bd8 | ||
|
|
4991ad8f1c | ||
|
|
c5136a1808 | ||
|
|
446d882eec | ||
|
|
b3e207a967 | ||
|
|
5c25345cf8 | ||
|
|
a01a5055a0 | ||
|
|
234aae3783 | ||
|
|
ca45137cc6 | ||
|
|
bc3d16b40e | ||
|
|
66e212d30c | ||
|
|
b69811479f | ||
|
|
43c5d041ef | ||
|
|
dfe9792330 | ||
|
|
250df57bd0 | ||
|
|
02b8ed2b5d | ||
|
|
71c1445439 | ||
|
|
d86299cdf6 | ||
|
|
1b86fba3e0 | ||
|
|
3ee7c92cdd | ||
|
|
6c6cd130aa | ||
|
|
65a1d44069 | ||
|
|
11312a5e27 | ||
|
|
6b13958ac0 | ||
|
|
3142daafd3 | ||
|
|
4bef78f847 | ||
|
|
82be86e086 | ||
|
|
bff505ef25 | ||
|
|
533f5671c2 | ||
|
|
8c7547b485 | ||
|
|
741c194bb8 | ||
|
|
d2bdfd8dac | ||
|
|
36c67fbe20 | ||
|
|
8fd1aede2a | ||
|
|
287ae1f0b1 | ||
|
|
903361cb58 | ||
|
|
c8cf412a4a | ||
|
|
affc249012 | ||
|
|
653671ea79 | ||
|
|
7185908682 | ||
|
|
675da8d5d8 | ||
|
|
e91becee0d | ||
|
|
18732efe75 | ||
|
|
63897fd914 | ||
|
|
9b865af43b | ||
|
|
b78275734c | ||
|
|
00a6b0d1f8 | ||
|
|
13fe6f5e51 | ||
|
|
bc0c3a18d7 | ||
|
|
8f9b7eba16 | ||
|
|
48eacb2e1c | ||
|
|
2168814814 | ||
|
|
972a2829d7 | ||
|
|
dbf5d99622 | ||
|
|
f45721ba42 | ||
|
|
9034968868 | ||
|
|
bcb9bacea5 | ||
|
|
4b922da294 | ||
|
|
6d90314492 | ||
|
|
93b02d37ed | ||
|
|
c11ddd84ab | ||
|
|
518355a68a | ||
|
|
74ebeb4844 |
2
.env
2
.env
@@ -1,2 +1,2 @@
|
||||
REGISTRY_PREFIX=harbor.sheldan.dev/abstracto/
|
||||
VERSION=1.5.25
|
||||
VERSION=1.5.49
|
||||
25
.github/workflows/build.yml
vendored
25
.github/workflows/build.yml
vendored
@@ -16,7 +16,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -25,17 +25,16 @@ jobs:
|
||||
with:
|
||||
distribution: 'corretto'
|
||||
java-version: 17
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '21.x'
|
||||
- name: Build with Maven
|
||||
run: mvn -B install --file abstracto-application/pom.xml
|
||||
- uses: actions/setup-ruby@v1
|
||||
- name: Send Webhook Notification
|
||||
if: always()
|
||||
env:
|
||||
JOB_STATUS: ${{ job.status }}
|
||||
WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }}
|
||||
HOOK_OS_NAME: ${{ runner.os }}
|
||||
WORKFLOW_NAME: ${{ github.workflow }}
|
||||
run: |
|
||||
git clone https://github.com/DiscordHooks/github-actions-discord-webhook.git webhook
|
||||
bash webhook/send.sh $JOB_STATUS $WEBHOOK_URL
|
||||
shell: bash
|
||||
- name: Install node dependencies and build
|
||||
working-directory: ./ui/experience-tracking
|
||||
run: npm ci
|
||||
- name: Build ui application
|
||||
working-directory: ./ui/experience-tracking
|
||||
run: npm run build
|
||||
|
||||
|
||||
25
.github/workflows/release_manual.yml
vendored
25
.github/workflows/release_manual.yml
vendored
@@ -1,8 +1,11 @@
|
||||
name: Publishes a new version of abstracto
|
||||
on: workflow_dispatch
|
||||
permissions:
|
||||
packages: write
|
||||
contents: write
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -12,10 +15,20 @@ jobs:
|
||||
with:
|
||||
distribution: 'corretto'
|
||||
java-version: 17
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '21.x'
|
||||
- name: Load current version
|
||||
id: version
|
||||
working-directory: ./abstracto-application
|
||||
run: echo "version=$(mvn -q -Dexec.executable="echo" -Dexec.args='${project.version}' --non-recursive exec:exec | cut -d- -f1)" >> $GITHUB_ENV
|
||||
- name: Create a Release
|
||||
uses: elgohr/Github-Release-Action@v5
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
title: Release of version ${{ env.version }}
|
||||
- name: Release maven packages
|
||||
uses: qcastel/github-actions-maven-release@v1.12.41
|
||||
env:
|
||||
@@ -28,6 +41,14 @@ jobs:
|
||||
release-branch-name: master
|
||||
maven-args: "-Dmaven.javadoc.skip=true -s settings.xml -DskipTests"
|
||||
access-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install node dependencies and build
|
||||
working-directory: ./ui/experience-tracking
|
||||
run: npm ci
|
||||
- name: Build ui application
|
||||
working-directory: ./ui/experience-tracking
|
||||
run: npm run build
|
||||
- name: Copy built UI
|
||||
run: cp -R ui/experience-tracking/build/* python/components/experience-tracking/resources/templates/experience/leaderboards/
|
||||
- name: Login to Harbor
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
@@ -43,7 +64,7 @@ jobs:
|
||||
with:
|
||||
path: .env
|
||||
- name: Build and push Docker containers
|
||||
run: docker-compose build && docker-compose push
|
||||
run: docker compose build && docker compose push
|
||||
env:
|
||||
REGISTRY_PREFIX: ${{ steps.dotenv.outputs.registry_prefix }}
|
||||
VERSION: ${{ steps.dotenv.outputs.version }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,9 +14,7 @@ target/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Sheldan
|
||||
Copyright (c) 2024 Sheldan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -8,11 +8,10 @@ Abstracto represents a framework to be used as a basis for a Discord bot. It use
|
||||
and provides an extensive tool set to create new commands and a wide range of commands out of the box.
|
||||
|
||||
This repository does not provide the full functionality in order to start a discord bot, because it requires a Main class.
|
||||
An example implementation of this bot can be seen [here](https://github.com/Sheldan/Crimson). This repository contains the required configuration in order to run a bot and example customizations.
|
||||
|
||||
|
||||
## Technologies
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 5.0.0-beta.13
|
||||
* [JDA](https://github.com/DV8FromTheWorld/JDA/) The Discord API Wrapper in the version 5.0.0-beta.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.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>anti-raid</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>assignable-roles</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>assignable-roles-int</artifactId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>custom-command</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>dynamic-activity</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.sheldan.abstracto.entertainment.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CombinedParameterEntry;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
@@ -86,7 +87,7 @@ public class Mock extends AbstractConditionableCommand {
|
||||
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));
|
||||
parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(CombinedParameterEntry.messageParameter(Message.class), CombinedParameterEntry.parameter(String.class)));
|
||||
|
||||
Parameter messageParameter = Parameter
|
||||
.builder()
|
||||
|
||||
@@ -105,7 +105,9 @@ public class EntertainmentServiceBean implements EntertainmentService {
|
||||
|
||||
@Override
|
||||
public Integer getLoveCalcValue(String firstPart, String secondPart) {
|
||||
return secureRandom.nextInt(100);
|
||||
String fullInput = firstPart.toLowerCase() + secondPart.toLowerCase();
|
||||
Random random = new Random(fullInput.hashCode());
|
||||
return random.nextInt(100);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>entertainment</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>experience-tracking</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -38,6 +38,21 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.core</groupId>
|
||||
<artifactId>core-int</artifactId>
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package dev.sheldan.abstracto.experience.api;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.frontend.RoleDisplay;
|
||||
import dev.sheldan.abstracto.core.service.GuildService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.model.api.ExperienceConfig;
|
||||
import dev.sheldan.abstracto.experience.model.api.ExperienceRoleDisplay;
|
||||
import dev.sheldan.abstracto.experience.model.template.LevelRole;
|
||||
import dev.sheldan.abstracto.experience.service.ExperienceRoleService;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/experience/v1/")
|
||||
public class ExperienceConfigController {
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private ExperienceRoleService experienceRoleService;
|
||||
|
||||
@Autowired
|
||||
private GuildService guildService;
|
||||
|
||||
@GetMapping(value = "/leaderboards/{serverId}/config", produces = "application/json")
|
||||
public ExperienceConfig getLeaderboard(@PathVariable("serverId") Long serverId) {
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
List<LevelRole> levelRoles = experienceRoleService.loadLevelRoleConfigForServer(server);
|
||||
levelRoles = levelRoles.stream().sorted(Comparator.comparingInt(LevelRole::getLevel).reversed()).toList();
|
||||
Guild guild = guildService.getGuildById(serverId);
|
||||
List<ExperienceRoleDisplay> roles = levelRoles
|
||||
.stream()
|
||||
.map(levelRole -> convertRole(levelRole, guild))
|
||||
.toList();
|
||||
return ExperienceConfig
|
||||
.builder()
|
||||
.roles(roles)
|
||||
.build();
|
||||
}
|
||||
|
||||
private ExperienceRoleDisplay convertRole(LevelRole levelRole, Guild guild) {
|
||||
Role guildRole = guild.getRoleById(levelRole.getRoleId());
|
||||
RoleDisplay roleDisplay;
|
||||
if(guildRole != null) {
|
||||
roleDisplay = RoleDisplay.fromRole(guildRole);
|
||||
} else {
|
||||
roleDisplay = RoleDisplay
|
||||
.builder()
|
||||
.id(String.valueOf(levelRole.getRoleId()))
|
||||
.build();
|
||||
}
|
||||
return ExperienceRoleDisplay
|
||||
.builder()
|
||||
.level(levelRole.getLevel())
|
||||
.role(roleDisplay)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package dev.sheldan.abstracto.experience.api;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.frontend.RoleDisplay;
|
||||
import dev.sheldan.abstracto.core.models.frontend.UserDisplay;
|
||||
import dev.sheldan.abstracto.core.service.GuildService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.model.api.UserExperienceDisplay;
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceRole;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.service.ExperienceLevelService;
|
||||
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.entities.UserSnowflake;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/experience/v1")
|
||||
public class LeaderboardController {
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserExperienceManagementService userExperienceManagementService;
|
||||
|
||||
@Autowired
|
||||
private GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
private ExperienceLevelService experienceLevelService;
|
||||
|
||||
@GetMapping(value = "/leaderboards/{serverId}", produces = "application/json")
|
||||
public Page<UserExperienceDisplay> getLeaderboard(@PathVariable("serverId") Long serverId,
|
||||
@PageableDefault(value = 25, page = 0)
|
||||
@SortDefault(sort = "experience", direction = Sort.Direction.DESC)
|
||||
Pageable pageable) {
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
Guild guild = guildService.getGuildById(serverId);
|
||||
Page<AUserExperience> allElements = userExperienceManagementService.loadAllUsersPaginated(server, pageable);
|
||||
return allElements
|
||||
.map(userExperience -> convertFromUser(guild, userExperience, pageable, allElements));
|
||||
}
|
||||
|
||||
private UserExperienceDisplay convertFromUser(Guild guild, AUserExperience aUserExperience, Pageable pageable, Page<AUserExperience> page) {
|
||||
Long userId = aUserExperience.getUser().getUserReference().getId();
|
||||
Member member = guild.getMember(UserSnowflake.fromId(userId));
|
||||
AExperienceRole experienceRole = aUserExperience.getCurrentExperienceRole();
|
||||
UserDisplay userDisplay = null;
|
||||
RoleDisplay roleDisplay = null;
|
||||
Long experienceNeededToNextLevel = experienceLevelService.calculateExperienceToNextLevel(aUserExperience.getCurrentLevel().getLevel(), aUserExperience.getExperience());
|
||||
Long nextLevelExperience = experienceLevelService.calculateNextLevel(aUserExperience.getCurrentLevel().getLevel()).getExperienceNeeded();
|
||||
if(experienceRole != null) {
|
||||
Role role = guild.getRoleById(experienceRole.getRole().getId());
|
||||
if(role != null) {
|
||||
roleDisplay = RoleDisplay.fromRole(role);
|
||||
} else {
|
||||
roleDisplay = RoleDisplay.fromARole(experienceRole.getRole());
|
||||
}
|
||||
}
|
||||
if(member != null) {
|
||||
userDisplay = UserDisplay.fromMember(member);
|
||||
}
|
||||
Long currentExpNeeded = aUserExperience.getCurrentLevel().getExperienceNeeded();
|
||||
Long experienceWithinLevel = aUserExperience.getExperience() - currentExpNeeded;
|
||||
Long experienceNeededForCurrentLevel = nextLevelExperience - currentExpNeeded;
|
||||
return UserExperienceDisplay
|
||||
.builder()
|
||||
.id(String.valueOf(userId))
|
||||
.messages(aUserExperience.getMessageCount())
|
||||
.level(aUserExperience.getLevelOrDefault())
|
||||
.rank((int) pageable.getOffset() + page.getContent().indexOf(aUserExperience) + 1)
|
||||
.experience(aUserExperience.getExperience())
|
||||
.experienceToNextLevel(experienceNeededToNextLevel)
|
||||
.currentLevelExperienceNeeded(experienceNeededForCurrentLevel)
|
||||
.experienceOnCurrentLevel(experienceWithinLevel)
|
||||
.percentage(((float) experienceWithinLevel / experienceNeededForCurrentLevel) * 100)
|
||||
.nextLevelExperienceNeeded(nextLevelExperience)
|
||||
.role(roleDisplay)
|
||||
.member(userDisplay)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
package dev.sheldan.abstracto.experience.command;
|
||||
|
||||
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.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandAutoCompleteService;
|
||||
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.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureMode;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
|
||||
import dev.sheldan.abstracto.experience.exception.LevelActionAlreadyExistsException;
|
||||
import dev.sheldan.abstracto.experience.exception.LevelActionNotFoundException;
|
||||
import dev.sheldan.abstracto.experience.listener.LevelActionListener;
|
||||
import dev.sheldan.abstracto.experience.model.LevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.service.LevelActionService;
|
||||
import dev.sheldan.abstracto.experience.service.management.LevelActionManagementService;
|
||||
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
|
||||
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.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AddLevelAction extends AbstractConditionableCommand {
|
||||
|
||||
private static final String COMMAND_NAME = "addLevelAction";
|
||||
private static final String ACTION_PARAMETER_NAME = "action";
|
||||
private static final String LEVEL_PARAMETER_NAME = "level";
|
||||
private static final String PARAMETER_PARAMETER_NAME = "parameter";
|
||||
private static final String MEMBER_PARAMETER_NAME = "member";
|
||||
|
||||
private static final String RESPONSE_TEMPLATE = "addLevelAction_response";
|
||||
|
||||
@Autowired
|
||||
private LevelActionManagementService levelActionManagementService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandAutoCompleteService slashCommandAutoCompleteService;
|
||||
|
||||
@Autowired
|
||||
private LevelActionService levelActionService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserExperienceManagementService userExperienceManagementService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
String actionName = slashCommandParameterService.getCommandOption(ACTION_PARAMETER_NAME, event, String.class);
|
||||
LevelActionListener listener = levelActionService.getLevelActionListenerForName(actionName)
|
||||
.orElseThrow(LevelActionNotFoundException::new);
|
||||
AUserInAServer aUserInAServer;
|
||||
if(slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER_NAME, event)) {
|
||||
Member member = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER_NAME, event, Member.class);
|
||||
aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
} else {
|
||||
aUserInAServer = null;
|
||||
}
|
||||
Integer level = slashCommandParameterService.getCommandOption(LEVEL_PARAMETER_NAME, event, Integer.class);
|
||||
String parameter = slashCommandParameterService.getCommandOption(PARAMETER_PARAMETER_NAME, event, String.class);
|
||||
LevelActionPayload payload = listener.createPayload(event.getGuild(), parameter);
|
||||
AServer server = serverManagementService.loadServer(event.getGuild());
|
||||
log.info("Adding level action {} for level {} in server {}.", actionName, level, event.getGuild().getId());
|
||||
AUserExperience userExperience = null;
|
||||
if(aUserInAServer != null) {
|
||||
Optional<AUserExperience> aUserExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(aUserInAServer.getUserInServerId());
|
||||
userExperience = aUserExperienceOptional.orElseGet(() -> {
|
||||
AUserExperience user = userExperienceManagementService.createUserInServer(aUserInAServer);
|
||||
return userExperienceManagementService.saveUser(user);
|
||||
});
|
||||
}
|
||||
if(levelActionManagementService.getLevelAction(actionName, level, server, userExperience).isPresent()) {
|
||||
throw new LevelActionAlreadyExistsException();
|
||||
}
|
||||
levelActionManagementService.createLevelAction(level, server, actionName, userExperience, payload);
|
||||
return interactionService.replyEmbed(RESPONSE_TEMPLATE, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> performAutoComplete(CommandAutoCompleteInteractionEvent event) {
|
||||
if(slashCommandAutoCompleteService.matchesParameter(event.getFocusedOption(), ACTION_PARAMETER_NAME)) {
|
||||
String input = event.getFocusedOption().getValue().toLowerCase();
|
||||
List<String> availableLevelActions = levelActionService.getAvailableLevelActions()
|
||||
.stream()
|
||||
.map(String::toLowerCase)
|
||||
.toList();
|
||||
if(!input.isEmpty()) {
|
||||
return availableLevelActions.stream().filter(s -> s.startsWith(input)).toList();
|
||||
} else {
|
||||
return availableLevelActions;
|
||||
}
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
Parameter actionParameter = Parameter
|
||||
.builder()
|
||||
.name(ACTION_PARAMETER_NAME)
|
||||
.templated(true)
|
||||
.type(String.class)
|
||||
.supportsAutoComplete(true)
|
||||
.build();
|
||||
|
||||
Parameter levelParameter = Parameter
|
||||
.builder()
|
||||
.name(LEVEL_PARAMETER_NAME)
|
||||
.templated(true)
|
||||
.type(Integer.class)
|
||||
.build();
|
||||
|
||||
Parameter parameterParameter = Parameter
|
||||
.builder()
|
||||
.name(PARAMETER_PARAMETER_NAME)
|
||||
.templated(true)
|
||||
.type(String.class)
|
||||
.build();
|
||||
|
||||
Parameter memberParameter = Parameter
|
||||
.builder()
|
||||
.name(MEMBER_PARAMETER_NAME)
|
||||
.templated(true)
|
||||
.optional(true)
|
||||
.type(Member.class)
|
||||
.build();
|
||||
|
||||
List<Parameter> parameters = Arrays.asList(levelParameter, actionParameter, parameterParameter, memberParameter);
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
|
||||
.groupName("levelAction")
|
||||
.commandName("add")
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(COMMAND_NAME)
|
||||
.module(ExperienceModuleDefinition.EXPERIENCE)
|
||||
.templated(true)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.slashCommandOnly(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ExperienceFeatureDefinition.EXPERIENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(ExperienceFeatureMode.LEVEL_ACTION);
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,14 @@ 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.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureMode;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
|
||||
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@@ -100,4 +102,10 @@ public class ExpLevelUpNotification extends AbstractConditionableCommand {
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(ExperienceFeatureMode.LEVEL_UP_NOTIFICATION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,9 @@ import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -70,6 +72,9 @@ public class LeaderBoardCommand extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Value("${abstracto.experience.leaderboard.externalUrl}")
|
||||
private String leaderboardExternalURL;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
@@ -91,11 +96,18 @@ public class LeaderBoardCommand extends AbstractConditionableCommand {
|
||||
LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(aUserInAServer);
|
||||
CompletableFuture<List<LeaderBoardEntryModel>> userRankFuture = converter.fromLeaderBoardEntry(Arrays.asList(userRank));
|
||||
futures.add(userRankFuture);
|
||||
String leaderboardUrl;
|
||||
if(!StringUtils.isBlank(leaderboardExternalURL)) {
|
||||
leaderboardUrl = String.format("%s/experience/leaderboards/%s", leaderboardExternalURL, actorUser.getGuild().getIdLong());
|
||||
} else {
|
||||
leaderboardUrl = null;
|
||||
}
|
||||
return FutureUtils.toSingleFuture(futures).thenCompose(aVoid -> {
|
||||
List<LeaderBoardEntryModel> finalModels = completableFutures.join();
|
||||
LeaderBoardModel leaderBoardModel = LeaderBoardModel
|
||||
.builder()
|
||||
.userExperiences(finalModels)
|
||||
.leaderboardUrl(leaderboardUrl)
|
||||
.userExecuting(userRankFuture.join().get(0))
|
||||
.build();
|
||||
return CompletableFuture.completedFuture(templateService.renderEmbedTemplate(LEADER_BOARD_POST_EMBED_TEMPLATE, leaderBoardModel, actorUser.getGuild().getIdLong()));
|
||||
|
||||
@@ -107,13 +107,13 @@ public class Rank extends AbstractConditionableCommand {
|
||||
Long currentExpNeeded = experienceObj.getCurrentLevel().getExperienceNeeded();
|
||||
Long experienceNeededToNextLevel = experienceLevelService.calculateExperienceToNextLevel(experienceObj.getCurrentLevel().getLevel(), experienceObj.getExperience());
|
||||
Long nextLevelExperience = experienceLevelService.calculateNextLevel(experienceObj.getCurrentLevel().getLevel()).getExperienceNeeded();
|
||||
Long levelExperience = nextLevelExperience - currentExpNeeded;
|
||||
Long inLevelExperience = experienceObj.getExperience() - currentExpNeeded;
|
||||
Long experienceNeededForCurrentLevel = nextLevelExperience - currentExpNeeded;
|
||||
Long experienceWithinLevel = experienceObj.getExperience() - currentExpNeeded;
|
||||
rankModel.setExperienceForCurrentLevel(currentExpNeeded);
|
||||
rankModel.setCurrentLevelPercentage(((float) inLevelExperience / levelExperience) * 100);
|
||||
rankModel.setLevelExperience(levelExperience);
|
||||
rankModel.setCurrentLevelPercentage(((float) experienceWithinLevel / experienceNeededForCurrentLevel) * 100);
|
||||
rankModel.setLevelExperience(experienceNeededForCurrentLevel);
|
||||
rankModel.setExperienceToNextLevel(experienceNeededToNextLevel);
|
||||
rankModel.setInLevelExperience(inLevelExperience);
|
||||
rankModel.setInLevelExperience(experienceWithinLevel);
|
||||
rankModel.setNextLevelExperience(nextLevelExperience);
|
||||
return templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel, toRender.getGuild().getIdLong());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package dev.sheldan.abstracto.experience.command;
|
||||
|
||||
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.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandAutoCompleteService;
|
||||
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.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureMode;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
|
||||
import dev.sheldan.abstracto.experience.exception.LevelActionNotFoundException;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.service.management.LevelActionManagementService;
|
||||
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
|
||||
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.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RemoveLevelAction extends AbstractConditionableCommand {
|
||||
|
||||
private static final String COMMAND_NAME = "removeLevelAction";
|
||||
private static final String ACTION_PARAMETER_NAME = "action";
|
||||
private static final String LEVEL_PARAMETER_NAME = "level";
|
||||
private static final String MEMBER_PARAMETER_NAME = "member";
|
||||
|
||||
private static final String RESPONSE_TEMPLATE = "removeLevelAction_response";
|
||||
|
||||
@Autowired
|
||||
private LevelActionManagementService levelActionManagementService;
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandParameterService slashCommandParameterService;
|
||||
|
||||
@Autowired
|
||||
private SlashCommandAutoCompleteService slashCommandAutoCompleteService;
|
||||
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private UserExperienceManagementService userExperienceManagementService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
String actionName = slashCommandParameterService.getCommandOption(ACTION_PARAMETER_NAME, event, String.class);
|
||||
AUserExperience userExperience = null;
|
||||
if(slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER_NAME, event)) {
|
||||
Member member = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER_NAME, event, Member.class);
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
userExperience = userExperienceManagementService.findUserInServer(aUserInAServer);
|
||||
}
|
||||
Integer level = slashCommandParameterService.getCommandOption(LEVEL_PARAMETER_NAME, event, Integer.class);
|
||||
AServer server = serverManagementService.loadServer(event.getGuild());
|
||||
log.info("Removing level action {} for level {} in server {}.", actionName, level, event.getGuild().getId());
|
||||
if(levelActionManagementService.getLevelAction(actionName, level, server, userExperience).isEmpty()) {
|
||||
throw new LevelActionNotFoundException();
|
||||
}
|
||||
levelActionManagementService.deleteLevelAction(level, server, actionName, userExperience);
|
||||
return interactionService.replyEmbed(RESPONSE_TEMPLATE, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> performAutoComplete(CommandAutoCompleteInteractionEvent event) {
|
||||
if(slashCommandAutoCompleteService.matchesParameter(event.getFocusedOption(), ACTION_PARAMETER_NAME)) {
|
||||
String input = event.getFocusedOption().getValue().toLowerCase();
|
||||
AServer server = serverManagementService.loadServer(event.getGuild());
|
||||
Set<String> availableLevelActions = levelActionManagementService.getLevelActionsOfServer(server)
|
||||
.stream()
|
||||
.map(levelAction -> levelAction.getAction().toLowerCase())
|
||||
.collect(Collectors.toSet());
|
||||
if(!input.isEmpty()) {
|
||||
return availableLevelActions.stream().filter(s -> s.startsWith(input)).toList();
|
||||
} else {
|
||||
return new ArrayList<>(availableLevelActions);
|
||||
}
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
Parameter actionParameter = Parameter
|
||||
.builder()
|
||||
.name(ACTION_PARAMETER_NAME)
|
||||
.templated(true)
|
||||
.type(String.class)
|
||||
.supportsAutoComplete(true)
|
||||
.build();
|
||||
|
||||
Parameter levelParameter = Parameter
|
||||
.builder()
|
||||
.name(LEVEL_PARAMETER_NAME)
|
||||
.templated(true)
|
||||
.type(Integer.class)
|
||||
.build();
|
||||
|
||||
Parameter memberParameter = Parameter
|
||||
.builder()
|
||||
.name(MEMBER_PARAMETER_NAME)
|
||||
.templated(true)
|
||||
.optional(true)
|
||||
.type(Member.class)
|
||||
.build();
|
||||
|
||||
List<Parameter> parameters = Arrays.asList(levelParameter, actionParameter, memberParameter);
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
|
||||
.groupName("levelAction")
|
||||
.commandName("remove")
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(COMMAND_NAME)
|
||||
.module(ExperienceModuleDefinition.EXPERIENCE)
|
||||
.templated(true)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.slashCommandOnly(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ExperienceFeatureDefinition.EXPERIENCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(ExperienceFeatureMode.LEVEL_ACTION);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package dev.sheldan.abstracto.experience.command;
|
||||
|
||||
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.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureMode;
|
||||
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||
import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureMode;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
|
||||
import dev.sheldan.abstracto.experience.model.template.LevelActionsDisplay;
|
||||
import dev.sheldan.abstracto.experience.service.LevelActionService;
|
||||
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 ShowLevelActions extends AbstractConditionableCommand {
|
||||
|
||||
private static final String COMMAND_NAME = "showLevelActions";
|
||||
private static final String TEMPLATE_KEY = "showLevelActions_response";
|
||||
|
||||
@Autowired
|
||||
private InteractionService interactionService;
|
||||
|
||||
@Autowired
|
||||
private LevelActionService levelActionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
|
||||
LevelActionsDisplay levelActionsToDisplay = levelActionService.getLevelActionsToDisplay(event.getGuild());
|
||||
return interactionService.replyEmbed(TEMPLATE_KEY, levelActionsToDisplay, event)
|
||||
.thenApply(interactionHook -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
HelpInfo helpInfo = HelpInfo
|
||||
.builder()
|
||||
.templated(true)
|
||||
.build();
|
||||
|
||||
SlashCommandConfig slashCommandConfig = SlashCommandConfig
|
||||
.builder()
|
||||
.enabled(true)
|
||||
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
|
||||
.groupName("levelAction")
|
||||
.commandName("show")
|
||||
.build();
|
||||
|
||||
return CommandConfiguration.builder()
|
||||
.name(COMMAND_NAME)
|
||||
.module(ExperienceModuleDefinition.EXPERIENCE)
|
||||
.templated(true)
|
||||
.slashCommandConfig(slashCommandConfig)
|
||||
.supportsEmbedException(true)
|
||||
.slashCommandOnly(true)
|
||||
.causesReaction(true)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getFeatureModeLimitations() {
|
||||
return Arrays.asList(ExperienceFeatureMode.LEVEL_ACTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return ExperienceFeatureDefinition.EXPERIENCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.utils.ParseUtils;
|
||||
import dev.sheldan.abstracto.experience.model.*;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AddMemberToChannelLevelAction implements LevelActionListener {
|
||||
|
||||
public static final String ADD_MEMBER_TO_CHANNEL_ABOVE_LEVEL = "add_member_to_channel_above_level";
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container) {
|
||||
AddMemberToChannelLevelActionPayload payload = (AddMemberToChannelLevelActionPayload) levelAction.getLoadedPayload();
|
||||
log.info("Adding member {} to channel {} in server {}.", userExperience.getUser().getUserReference().getId(), payload.getChannelId(), userExperience.getServer().getId());
|
||||
container.getChannelsToAdd().add(payload.getChannelId());
|
||||
container.getChannelsToRemove().remove(payload.getChannelId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareAction(LevelAction levelAction) {
|
||||
levelAction.setLoadedPayload(gson.fromJson(levelAction.getPayload(), AddMemberToChannelLevelActionPayload.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddMemberToChannelLevelActionPayload createPayload(Guild guild, String input) {
|
||||
GuildChannel channel = ParseUtils.parseGuildChannelFromText(input, guild);
|
||||
return AddMemberToChannelLevelActionPayload
|
||||
.builder()
|
||||
.channelId(channel.getIdLong())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ADD_MEMBER_TO_CHANNEL_ABOVE_LEVEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.utils.ParseUtils;
|
||||
import dev.sheldan.abstracto.experience.model.*;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AddRoleLevelAction implements LevelActionListener {
|
||||
|
||||
public static final String ADD_ROLE_ABOVE_LEVEL = "add_role_above_level";
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container) {
|
||||
AddRoleLevelActionPayload payload = (AddRoleLevelActionPayload) levelAction.getLoadedPayload();
|
||||
log.info("Adding role {} to user {} in server {}.", payload.getRoleId(), userExperience.getUser().getUserReference().getId(), userExperience.getServer().getId());
|
||||
container.getRolesToAdd().add(payload.getRoleId());
|
||||
container.getRolesToRemove().remove(payload.getRoleId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareAction(LevelAction levelAction) {
|
||||
levelAction.setLoadedPayload(gson.fromJson(levelAction.getPayload(), AddRoleLevelActionPayload.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelActionPayload createPayload(Guild guild, String input) {
|
||||
Role role = ParseUtils.parseRoleFromText(input, guild);
|
||||
return AddRoleLevelActionPayload
|
||||
.builder()
|
||||
.roleId(role.getIdLong())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ADD_ROLE_ABOVE_LEVEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,10 +6,13 @@ import dev.sheldan.abstracto.core.listener.async.jda.AsyncJoinListener;
|
||||
import dev.sheldan.abstracto.core.listener.sync.jda.JoinListener;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.listener.MemberJoinModel;
|
||||
import dev.sheldan.abstracto.core.service.FeatureModeService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureMode;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
|
||||
import dev.sheldan.abstracto.experience.service.LevelActionService;
|
||||
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@@ -35,6 +38,12 @@ public class JoiningUserRoleListener implements AsyncJoinListener {
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
@Autowired
|
||||
private LevelActionService levelActionService;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MemberJoinModel model) {
|
||||
if(model.getMember().isPending()) {
|
||||
@@ -43,12 +52,24 @@ public class JoiningUserRoleListener implements AsyncJoinListener {
|
||||
}
|
||||
Optional<AUserInAServer> userInAServerOptional = userInServerManagementService.loadUserOptional(model.getServerId(), model.getJoiningUser().getUserId());
|
||||
userInAServerOptional.ifPresent(aUserInAServer -> {
|
||||
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(aUserInAServer.getUserInServerId());
|
||||
Long userInServerId = aUserInAServer.getUserInServerId();
|
||||
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(userInServerId);
|
||||
if(userExperienceOptional.isPresent()) {
|
||||
log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", model.getJoiningUser().getUserId(), model.getServerId());
|
||||
userExperienceService.syncForSingleUser(userExperienceOptional.get(), model.getMember(), true).thenAccept(result ->
|
||||
AUserExperience aUserExperience = userExperienceOptional.get();
|
||||
userExperienceService.syncForSingleUser(aUserExperience, model.getMember(), true).thenAccept(result ->
|
||||
log.info("Finished re-assigning experience for re-joining user {} in server {}.", model.getJoiningUser().getUserId(), model.getServerId())
|
||||
);
|
||||
if(featureModeService.featureModeActive(ExperienceFeatureDefinition.EXPERIENCE, aUserInAServer.getServerReference() , ExperienceFeatureMode.LEVEL_ACTION)) {
|
||||
levelActionService.applyLevelActionsToUser(aUserExperience)
|
||||
.thenAccept(unused -> {
|
||||
log.info("Executed level actions for user {}.", userInServerId);
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
log.warn("Failed to execute level actions for user {}.", userInServerId, throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
log.info("Joined user {} in server {} does not have any previous experience. Not setting up anything.", model.getJoiningUser().getUserId(), model.getServerId());
|
||||
}
|
||||
|
||||
@@ -5,10 +5,13 @@ import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
|
||||
import dev.sheldan.abstracto.core.listener.async.jda.AsyncUpdatePendingListener;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.models.listener.MemberUpdatePendingModel;
|
||||
import dev.sheldan.abstracto.core.service.FeatureModeService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
|
||||
import dev.sheldan.abstracto.experience.config.ExperienceFeatureMode;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
|
||||
import dev.sheldan.abstracto.experience.service.LevelActionService;
|
||||
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
@@ -34,16 +37,34 @@ public class MemberPendingRoleListener implements AsyncUpdatePendingListener {
|
||||
@Autowired
|
||||
private UserInServerManagementService userInServerManagementService;
|
||||
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
@Autowired
|
||||
private LevelActionService levelActionService;
|
||||
|
||||
@Override
|
||||
public DefaultListenerResult execute(MemberUpdatePendingModel model) {
|
||||
Optional<AUserInAServer> userInAServerOptional = userInServerManagementService.loadUserOptional(model.getServerId(), model.getUser().getUserId());
|
||||
userInAServerOptional.ifPresent(aUserInAServer -> {
|
||||
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(aUserInAServer.getUserInServerId());
|
||||
Long userInServerId = aUserInAServer.getUserInServerId();
|
||||
Optional<AUserExperience> userExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(userInServerId);
|
||||
if(userExperienceOptional.isPresent()) {
|
||||
log.info("User {} updated pending status {} with previous experience. Setting up experience role again (if necessary).", model.getUser().getUserId(), model.getServerId());
|
||||
userExperienceService.syncForSingleUser(userExperienceOptional.get(), model.getMember(), true).thenAccept(result ->
|
||||
AUserExperience aUserExperience = userExperienceOptional.get();
|
||||
userExperienceService.syncForSingleUser(aUserExperience, model.getMember(), true).thenAccept(result ->
|
||||
log.info("Finished re-assigning experience for update pending user {} in server {}.", model.getUser().getUserId(), model.getServerId())
|
||||
);
|
||||
if(featureModeService.featureModeActive(ExperienceFeatureDefinition.EXPERIENCE, aUserInAServer.getServerReference() , ExperienceFeatureMode.LEVEL_ACTION)) {
|
||||
levelActionService.applyLevelActionsToUser(aUserExperience)
|
||||
.thenAccept(unused -> {
|
||||
log.info("Executed level actions for user {}.", userInServerId);
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
log.warn("Failed to execute level actions for user {}.", userInServerId, throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
log.info("Member updating pending {} in server {} does not have any previous experience. Not setting up anything.", model.getUser().getUserId(), model.getServerId());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.utils.ParseUtils;
|
||||
import dev.sheldan.abstracto.experience.model.RemoveMemberFromChannelLevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RemoveMemberFromChannelLevelAction implements LevelActionListener {
|
||||
|
||||
public static final String REMOVE_MEMBER_FROM_CHANNEL_ABOVE_LEVEL = "remove_member_from_channel_above_level";
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container) {
|
||||
RemoveMemberFromChannelLevelActionPayload payload = (RemoveMemberFromChannelLevelActionPayload) levelAction.getLoadedPayload();
|
||||
log.info("Removing member {} from channel {} in server {}.", userExperience.getUser().getUserReference().getId(), payload.getChannelId(), userExperience.getServer().getId());
|
||||
container.getChannelsToRemove().add(payload.getChannelId());
|
||||
container.getChannelsToAdd().remove(payload.getChannelId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareAction(LevelAction levelAction) {
|
||||
levelAction.setLoadedPayload(gson.fromJson(levelAction.getPayload(), RemoveMemberFromChannelLevelActionPayload.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RemoveMemberFromChannelLevelActionPayload createPayload(Guild guild, String input) {
|
||||
GuildChannel channel = ParseUtils.parseGuildChannelFromText(input, guild);
|
||||
return RemoveMemberFromChannelLevelActionPayload
|
||||
.builder()
|
||||
.channelId(channel.getIdLong())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REMOVE_MEMBER_FROM_CHANNEL_ABOVE_LEVEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.utils.ParseUtils;
|
||||
import dev.sheldan.abstracto.experience.model.*;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class RemoveRoleLevelAction implements LevelActionListener {
|
||||
|
||||
public static final String REMOVE_ROLE_ABOVE_LEVEL = "remove_role_above_level";
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container) {
|
||||
RemoveRoleLevelActionPayload payload = (RemoveRoleLevelActionPayload) levelAction.getLoadedPayload();
|
||||
log.info("Removing role {} from user {} in server {}.", payload.getRoleId(), userExperience.getUser().getUserReference().getId(), userExperience.getServer().getId());
|
||||
container.getRolesToRemove().add(payload.getRoleId());
|
||||
container.getRolesToAdd().remove(payload.getRoleId());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void prepareAction(LevelAction levelAction) {
|
||||
levelAction.setLoadedPayload(gson.fromJson(levelAction.getPayload(), RemoveRoleLevelActionPayload.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelActionPayload createPayload(Guild guild, String input) {
|
||||
Role role = ParseUtils.parseRoleFromText(input, guild);
|
||||
return RemoveRoleLevelActionPayload
|
||||
.builder()
|
||||
.roleId(role.getIdLong())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REMOVE_ROLE_ABOVE_LEVEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.exception.InputFormatException;
|
||||
import dev.sheldan.abstracto.core.models.ServerUser;
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.MemberService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.core.utils.ParseUtils;
|
||||
import dev.sheldan.abstracto.experience.model.LevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.SendMessageToChannelLevelActionMessageModel;
|
||||
import dev.sheldan.abstracto.experience.model.SendMessageToChannelLevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
|
||||
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SendMessageToChannelLevelAction implements LevelActionListener {
|
||||
|
||||
public static final String ACTION_NAME = "send_message_to_channel_above_level";
|
||||
private static final String LEVEL_ACTION_SEND_MESSAGE_TEMPLATE_KEY = "levelAction_sendMessageToChannel_template";
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private TemplateService templateService;
|
||||
|
||||
@Autowired
|
||||
private MemberService memberService;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return ACTION_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container) {
|
||||
SendMessageToChannelLevelActionPayload payload = (SendMessageToChannelLevelActionPayload) levelAction.getLoadedPayload();
|
||||
SendMessageToChannelLevelActionMessageModel.SendMessageToChannelLevelActionMessageModelBuilder messageModelBuilder = SendMessageToChannelLevelActionMessageModel
|
||||
.builder()
|
||||
.level(userExperience.getLevelOrDefault())
|
||||
.templateKey(payload.getTemplateKey())
|
||||
.experience(userExperience.getExperience());
|
||||
ServerUser serverUser = ServerUser.fromAUserInAServer(userExperience.getUser());
|
||||
memberService.getMemberInServerAsync(serverUser).thenAccept(member -> {
|
||||
messageModelBuilder.memberDisplay(MemberDisplay.fromMember(member));
|
||||
SendMessageToChannelLevelActionMessageModel model = messageModelBuilder.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(LEVEL_ACTION_SEND_MESSAGE_TEMPLATE_KEY, model, serverUser.getServerId());
|
||||
GuildMessageChannel targetChannel = channelService.getMessageChannelFromServer(serverUser.getServerId(), payload.getChannelId());
|
||||
FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, targetChannel)).thenAccept(unused -> {
|
||||
log.info("Send message to channel action sent a message to channel {} for user {} in server {}.", payload.getChannelId(), serverUser.getUserId(), serverUser.getServerId());
|
||||
}).exceptionally(throwable -> {
|
||||
log.warn("Send message to channel action failed to send a message to channel {} for user {} in server {}.", payload.getChannelId(), serverUser.getUserId(), serverUser.getServerId(), throwable);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
log.warn("Failed to load member {} in server {} for send message level action towards channel {}.", serverUser.getUserId(), serverUser.getServerId(), payload.getChannelId());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction) {
|
||||
if(!oldLevel.equals(aUserExperience.getLevelOrDefault())) { // this means the user changed level now, this is the path from gaining a lot of experience
|
||||
boolean jumpedLevelToMatch = oldLevel < levelAction.getLevel().getLevel() && aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
// this boolean means that the user did NOT have the action earlier, but does now (and more than that)
|
||||
return jumpedLevelToMatch || aUserExperience.getLevelOrDefault().equals(levelAction.getLevel().getLevel()); // or the user matches the level _exactly_, this is the path from normally gaining experience
|
||||
} else {
|
||||
// This case is useful for re-joining, because this means, that the user did _not_ change level, and already is somewhere way above
|
||||
return aUserExperience.getLevelOrDefault() >= levelAction.getLevel().getLevel();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareAction(LevelAction levelAction) {
|
||||
levelAction.setLoadedPayload(gson.fromJson(levelAction.getPayload(), SendMessageToChannelLevelActionPayload.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelActionPayload createPayload(Guild guild, String input) {
|
||||
if(!input.contains(";")) {
|
||||
throw new InputFormatException(input, "<#channel>;template_key");
|
||||
}
|
||||
String channelPart = input.substring(0, input.indexOf(";"));
|
||||
GuildChannel channel = ParseUtils.parseGuildChannelFromText(channelPart, guild);
|
||||
String templateKey = input.substring(input.indexOf(";") + 1);
|
||||
return SendMessageToChannelLevelActionPayload
|
||||
.builder()
|
||||
.channelId(channel.getIdLong())
|
||||
.templateKey(templateKey)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class AddMemberToChannelLevelActionPayload implements LevelActionPayload {
|
||||
private Long channelId;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class AddRoleLevelActionPayload implements LevelActionPayload {
|
||||
private Long roleId;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class RemoveMemberFromChannelLevelActionPayload implements LevelActionPayload {
|
||||
private Long channelId;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class RemoveRoleLevelActionPayload implements LevelActionPayload {
|
||||
private Long roleId;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class SendMessageToChannelLevelActionMessageModel implements LevelActionPayload {
|
||||
private MemberDisplay memberDisplay;
|
||||
private Integer level;
|
||||
private Long experience;
|
||||
private String templateKey;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class SendMessageToChannelLevelActionPayload implements LevelActionPayload {
|
||||
private Long channelId;
|
||||
private String templateKey;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.abstracto.experience.model.api;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class ExperienceConfig {
|
||||
private List<ExperienceRoleDisplay> roles;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.abstracto.experience.model.api;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.frontend.RoleDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class ExperienceRoleDisplay {
|
||||
private RoleDisplay role;
|
||||
private Integer level;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.sheldan.abstracto.experience.model.api;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.frontend.RoleDisplay;
|
||||
import dev.sheldan.abstracto.core.models.frontend.UserDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class UserExperienceDisplay {
|
||||
private UserDisplay member;
|
||||
private String id;
|
||||
private Integer rank;
|
||||
private Integer level;
|
||||
private Long experience;
|
||||
private Long messages;
|
||||
private RoleDisplay role;
|
||||
private Long experienceToNextLevel;
|
||||
private Long experienceOnCurrentLevel;
|
||||
private Long currentLevelExperienceNeeded;
|
||||
private Float percentage;
|
||||
private Long nextLevelExperienceNeeded;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.sheldan.abstracto.experience.repository;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface LevelActionRepository extends JpaRepository<LevelAction, Long> {
|
||||
List<LevelAction> findByServerAndAffectedUserIsNullOrServerAndAffectedUser(AServer server, AServer server2, AUserExperience user);
|
||||
Optional<LevelAction> findByServerAndActionAndLevelOrAffectedUserAndLevelAndAction(AServer server, String action, AExperienceLevel level, AUserExperience user, AExperienceLevel level2, String action2);
|
||||
List<LevelAction> findByServer(AServer server);
|
||||
|
||||
void deleteByLevelAndActionAndServer(AExperienceLevel level, String action, AServer server);
|
||||
void deleteByLevelAndActionAndAffectedUser(AExperienceLevel level, String action, AUserExperience affectedUser);
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.experience.repository;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LeaderBoardEntryResult;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
@@ -24,6 +25,7 @@ public interface UserExperienceRepository extends JpaRepository<AUserExperience
|
||||
* @return A complete list of {@link AUserExperience} of the given {@link AServer server}
|
||||
*/
|
||||
List<AUserExperience> findByUser_ServerReference(AServer server);
|
||||
Page<AUserExperience> findAllByServer(AServer server, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Retrieves the {@link AUserExperience userExperience} ordered by experience, and applies the {@link Pageable pageable} to only filter out certain pages.
|
||||
|
||||
@@ -104,6 +104,9 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
@Autowired
|
||||
private FeatureModeService featureModeService;
|
||||
|
||||
@Autowired
|
||||
private LevelActionService levelActionService;
|
||||
|
||||
@Autowired
|
||||
private AUserExperienceServiceBean self;
|
||||
|
||||
@@ -306,25 +309,26 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
log.debug("User {} has a experience disable role in server {} - not giving any experience.", member.getIdLong(), serverId);
|
||||
return;
|
||||
}
|
||||
List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig();
|
||||
levels.sort(Comparator.comparing(AExperienceLevel::getExperienceNeeded));
|
||||
|
||||
Long minExp = configService.getLongValueOrConfigDefault(ExperienceFeatureConfig.MIN_EXP_KEY, serverId);
|
||||
Long maxExp = configService.getLongValueOrConfigDefault(ExperienceFeatureConfig.MAX_EXP_KEY, serverId);
|
||||
Double multiplier = configService.getDoubleValueOrConfigDefault(ExperienceFeatureConfig.EXP_MULTIPLIER_KEY, serverId);
|
||||
Long experienceRange = maxExp - minExp + 1;
|
||||
Long gainedExperience = (secureRandom.nextInt(experienceRange.intValue()) + minExp);
|
||||
gainedExperience = (long) Math.floor(gainedExperience * multiplier);
|
||||
|
||||
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
|
||||
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
|
||||
|
||||
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(member);
|
||||
Long userInServerId = userInAServer.getUserInServerId();
|
||||
log.debug("Handling {}. The user might gain {}.", userInServerId, gainedExperience);
|
||||
Optional<AUserExperience> aUserExperienceOptional = userExperienceManagementService.findByUserInServerIdOptional(userInAServer.getUserInServerId());
|
||||
AUserExperience aUserExperience = aUserExperienceOptional.orElseGet(() -> userExperienceManagementService.createUserInServer(userInAServer));
|
||||
if(Boolean.FALSE.equals(aUserExperience.getExperienceGainDisabled())) {
|
||||
List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig();
|
||||
levels.sort(Comparator.comparing(AExperienceLevel::getExperienceNeeded));
|
||||
|
||||
Long minExp = configService.getLongValueOrConfigDefault(ExperienceFeatureConfig.MIN_EXP_KEY, serverId);
|
||||
Long maxExp = configService.getLongValueOrConfigDefault(ExperienceFeatureConfig.MAX_EXP_KEY, serverId);
|
||||
Double multiplier = configService.getDoubleValueOrConfigDefault(ExperienceFeatureConfig.EXP_MULTIPLIER_KEY, serverId);
|
||||
Long experienceRange = maxExp - minExp + 1;
|
||||
Long gainedExperience = (secureRandom.nextInt(experienceRange.intValue()) + minExp);
|
||||
gainedExperience = (long) Math.floor(gainedExperience * multiplier);
|
||||
|
||||
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
|
||||
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));
|
||||
|
||||
log.debug("Handling {}. The user gains {}.", userInServerId, gainedExperience);
|
||||
|
||||
Long oldExperience = aUserExperience.getExperience();
|
||||
Long newExperienceCount = oldExperience + gainedExperience;
|
||||
aUserExperience.setExperience(newExperienceCount);
|
||||
@@ -332,8 +336,9 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
RoleCalculationResult result = RoleCalculationResult
|
||||
.builder()
|
||||
.build();
|
||||
if(!Objects.equals(newLevel.getLevel(), aUserExperience.getCurrentLevel().getLevel())) {
|
||||
Integer oldLevel = aUserExperience.getCurrentLevel() != null ? aUserExperience.getCurrentLevel().getLevel() : 0;
|
||||
boolean userChangesLevel = !Objects.equals(newLevel.getLevel(), aUserExperience.getCurrentLevel().getLevel());
|
||||
Integer oldLevel = aUserExperience.getCurrentLevel() != null ? aUserExperience.getCurrentLevel().getLevel() : 0;
|
||||
if(userChangesLevel) {
|
||||
log.info("User {} in server {} changed level. New {}, Old {}.", member.getIdLong(),
|
||||
member.getGuild().getIdLong(), newLevel.getLevel(),
|
||||
oldLevel);
|
||||
@@ -367,7 +372,17 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
aUserExperience.setCurrentExperienceRole(calculatedNewRole);
|
||||
}
|
||||
aUserExperience.setMessageCount(aUserExperience.getMessageCount() + 1L);
|
||||
if(!aUserExperienceOptional.isPresent()) {
|
||||
if(userChangesLevel && featureModeService.featureModeActive(ExperienceFeatureDefinition.EXPERIENCE, server, ExperienceFeatureMode.LEVEL_ACTION)) {
|
||||
levelActionService.applyLevelActionsToUser(aUserExperience, oldLevel)
|
||||
.thenAccept(unused -> {
|
||||
log.info("Executed level actions for user {}.", userInServerId);
|
||||
})
|
||||
.exceptionally(throwable -> {
|
||||
log.warn("Failed to execute level actions for user {}.", userInServerId, throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
if(aUserExperienceOptional.isEmpty()) {
|
||||
userExperienceManagementService.saveUser(aUserExperience);
|
||||
}
|
||||
if(!Objects.equals(result.getOldRoleId(), result.getNewRoleId())) {
|
||||
@@ -375,7 +390,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
roleService.updateRolesIds(member, Arrays.asList(result.getOldRoleId()), Arrays.asList(result.getNewRoleId())).thenAccept(unused -> {
|
||||
log.debug("Removed role {} from and added role {} to member {} in server {}.", result.getOldRoleId(), result.getNewRoleId(), member.getIdLong(), member.getGuild().getIdLong());
|
||||
}).exceptionally(throwable -> {
|
||||
log.warn("Failed to remove role {} from and add role {} to member {} in server {}.", result.getOldRoleId(), member.getIdLong(), member.getGuild().getIdLong(), throwable);
|
||||
log.warn("Failed to remove role {} from and add role {} to member {} in server {}.", result.getOldRoleId(), result.getNewRoleId(), member.getIdLong(), member.getGuild().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
} else {
|
||||
@@ -383,7 +398,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
roleService.removeRoleFromMemberAsync(member, result.getOldRoleId()).thenAccept(unused -> {
|
||||
log.debug("Removed role {} from member {} in server {}.", result.getOldRoleId(), member.getIdLong(), member.getGuild().getIdLong());
|
||||
}).exceptionally(throwable -> {
|
||||
log.warn("Failed to remove role {} from {} member {} in server {}.", result.getOldRoleId(), member.getIdLong(), member.getGuild().getIdLong(), throwable);
|
||||
log.warn("Failed to remove role {} from member {} in server {}.", result.getOldRoleId(), member.getIdLong(), member.getGuild().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@@ -391,7 +406,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
|
||||
roleService.addRoleToMemberAsync(member, result.getNewRoleId()).thenAccept(unused -> {
|
||||
log.debug("Added role {} to member {} in server {}.", result.getNewRoleId(), member.getIdLong(), member.getGuild().getIdLong());
|
||||
}).exceptionally(throwable -> {
|
||||
log.warn("Failed to add role {} to {} member {} in server {}.", result.getOldRoleId(), member.getIdLong(), member.getGuild().getIdLong(), throwable);
|
||||
log.warn("Failed to add role {} to member {} in server {}.", result.getOldRoleId(), member.getIdLong(), member.getGuild().getIdLong(), throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -166,7 +166,10 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
|
||||
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
|
||||
List<LevelRole> levelRoles = new ArrayList<>();
|
||||
roles.forEach(aExperienceRole -> {
|
||||
Role role = roleService.getRoleFromGuild(aExperienceRole.getRole());
|
||||
Role role = null;
|
||||
if(!aExperienceRole.getRole().getDeleted()) {
|
||||
role = roleService.getRoleFromGuild(aExperienceRole.getRole());
|
||||
}
|
||||
LevelRole levelRole = LevelRole
|
||||
.builder()
|
||||
.role(role)
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
package dev.sheldan.abstracto.experience.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import dev.sheldan.abstracto.core.service.ChannelService;
|
||||
import dev.sheldan.abstracto.core.service.GuildService;
|
||||
import dev.sheldan.abstracto.core.service.RoleService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||
import dev.sheldan.abstracto.experience.listener.LevelActionListener;
|
||||
import dev.sheldan.abstracto.experience.listener.MemberActionModification;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import dev.sheldan.abstracto.experience.model.template.LevelActionDisplay;
|
||||
import dev.sheldan.abstracto.experience.model.template.LevelActionsDisplay;
|
||||
import dev.sheldan.abstracto.experience.service.management.LevelActionManagementService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class LevelActionServiceBean implements LevelActionService {
|
||||
|
||||
@Autowired
|
||||
private LevelActionManagementService levelActionManagementService;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<LevelActionListener> levelActions = new ArrayList<>();
|
||||
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
|
||||
@Autowired
|
||||
private ChannelService channelService;
|
||||
|
||||
@Autowired
|
||||
private GuildService guildService;
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user) {
|
||||
return applyLevelActionsToUser(user, user.getLevelOrDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user, Integer oldLevel) {
|
||||
if(levelActions == null || levelActions.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
List<LevelAction> levelActionsOfUserInServer = levelActionManagementService.getLevelActionsOfUserInServer(user);
|
||||
if(levelActionsOfUserInServer.isEmpty()) {
|
||||
log.info("No actions available - no actions executed.");
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
Map<Integer, List<LevelAction>> actionConfigMap = new HashMap<>();
|
||||
|
||||
Map<String, LevelActionListener> actionStringListenerMap = levelActions
|
||||
.stream()
|
||||
.collect(Collectors.toMap(a -> a.getName().toLowerCase(), Function.identity()));
|
||||
|
||||
levelActionsOfUserInServer.forEach(levelAction -> {
|
||||
LevelActionListener listener = actionStringListenerMap.get(levelAction.getAction());
|
||||
if(listener == null) { // if for some reason the config is still in the database, but we don't have code for it anymore
|
||||
return;
|
||||
}
|
||||
if(!listener.shouldExecute(user, oldLevel, levelAction)) {
|
||||
return;
|
||||
}
|
||||
if(actionConfigMap.containsKey(levelAction.getLevel().getLevel())) {
|
||||
actionConfigMap.get(levelAction.getLevel().getLevel()).add(levelAction);
|
||||
} else {
|
||||
List<LevelAction> levelLevelActions = new ArrayList<>();
|
||||
levelLevelActions.add(levelAction);
|
||||
actionConfigMap.put(levelAction.getLevel().getLevel(), levelLevelActions);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
List<Integer> levels = actionConfigMap
|
||||
.keySet()
|
||||
.stream()
|
||||
.sorted()
|
||||
.toList();
|
||||
|
||||
log.debug("Performing actions for {} levels.", levels.size());
|
||||
|
||||
MemberActionModification modification = MemberActionModification
|
||||
.builder()
|
||||
.build();
|
||||
levels.forEach(level -> {
|
||||
List<LevelAction> actionsOnLevel = actionConfigMap.get(level);
|
||||
actionsOnLevel.forEach(levelAction -> {
|
||||
LevelActionListener listener = actionStringListenerMap.get(levelAction.getAction().toLowerCase());
|
||||
listener.prepareAction(levelAction);
|
||||
listener.apply(user, levelAction, modification);
|
||||
});
|
||||
});
|
||||
|
||||
return evaluateModifications(user, modification);
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> evaluateModifications(AUserExperience user, MemberActionModification modification) {
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
Long userId = user.getUser().getUserReference().getId();
|
||||
log.info("Updating user {}, rolesToAdd: {}, rolesToRemove: {}",
|
||||
userId, modification.getRolesToAdd().size(), modification.getRolesToRemove().size());
|
||||
if(!modification.getRolesToAdd().isEmpty() || !modification.getRolesToRemove().isEmpty()) {
|
||||
CompletableFuture<Void> roleFuture = roleService.updateRolesIds(user.getUser(), new ArrayList<>(modification.getRolesToAdd()), new ArrayList<>(modification.getRolesToRemove()));
|
||||
futures.add(roleFuture);
|
||||
}
|
||||
log.info("Updating user {}, channelsToAdd: {}, channelsToRemove: {}.", userId, modification.getChannelsToAdd().size(), modification.getChannelsToRemove().size());
|
||||
Guild guild = guildService.getGuildById(user.getServer().getId());
|
||||
EnumSet<Permission> permissions = EnumSet.of(Permission.VIEW_CHANNEL, Permission.MESSAGE_SEND);
|
||||
modification.getChannelsToAdd().forEach(channelId -> {
|
||||
futures.add(channelService.addMemberViewToChannel(guild, channelId, userId, permissions));
|
||||
});
|
||||
modification.getChannelsToRemove().forEach(channelId -> {
|
||||
futures.add(channelService.removeChannelOverrideForMember(guild, channelId, userId));
|
||||
});
|
||||
if(!futures.isEmpty()) {
|
||||
return new CompletableFutureList<>(futures).getMainFuture();
|
||||
} else {
|
||||
log.info("Actions resulted in no actions performed.");
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAvailableLevelActions() {
|
||||
return levelActions
|
||||
.stream()
|
||||
.map(LevelActionListener::getName)
|
||||
.map(String::toLowerCase)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<LevelActionListener> getLevelActionListenerForName(String name) {
|
||||
return levelActions
|
||||
.stream()
|
||||
.filter(levelActionListener -> levelActionListener.getName().equalsIgnoreCase(name))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<LevelAction> getLevelAction(AUserExperience userExperience, String action, Integer level) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelActionsDisplay getLevelActionsToDisplay(Guild guild) {
|
||||
AServer server = serverManagementService.loadServer(guild);
|
||||
List<LevelActionDisplay> actions = levelActionManagementService.getLevelActionsOfServer(server)
|
||||
.stream().map(levelAction -> LevelActionDisplay
|
||||
.builder()
|
||||
.actionKey(levelAction.getAction().toLowerCase())
|
||||
.level(levelAction.getLevel().getLevel())
|
||||
.parameters(levelAction.getPayload())
|
||||
.member(levelAction.getAffectedUser() != null ? MemberDisplay.fromAUserInAServer(levelAction.getAffectedUser().getUser()) : null)
|
||||
.build())
|
||||
.toList();
|
||||
return LevelActionsDisplay
|
||||
.builder()
|
||||
.actions(actions)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package dev.sheldan.abstracto.experience.service.management;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.experience.model.LevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import dev.sheldan.abstracto.experience.repository.LevelActionRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class LevelActionManagementServiceBean implements LevelActionManagementService {
|
||||
|
||||
@Autowired
|
||||
private LevelActionRepository levelActionRepository;
|
||||
|
||||
@Autowired
|
||||
private ExperienceLevelManagementService experienceLevelManagementService;
|
||||
|
||||
@Autowired
|
||||
private Gson gson;
|
||||
|
||||
@Override
|
||||
public LevelAction createLevelAction(Integer level, AServer server, String action, AUserExperience user, String payload) {
|
||||
AExperienceLevel experienceLevel = experienceLevelManagementService.getLevel(level);
|
||||
LevelAction levelAction = LevelAction
|
||||
.builder()
|
||||
.action(action)
|
||||
.affectedUser(user)
|
||||
.payload(payload)
|
||||
.server(server)
|
||||
.level(experienceLevel)
|
||||
.build();
|
||||
return levelActionRepository.save(levelAction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteLevelAction(Integer level, AServer server, String action, AUserExperience user) {
|
||||
AExperienceLevel experienceLevel = experienceLevelManagementService.getLevel(level);
|
||||
if(user == null) {
|
||||
levelActionRepository.deleteByLevelAndActionAndServer(experienceLevel, action, server);
|
||||
} else {
|
||||
levelActionRepository.deleteByLevelAndActionAndAffectedUser(experienceLevel, action, user);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelAction createLevelAction(Integer level, AServer server, String action, AUserExperience user, LevelActionPayload actionPayload) {
|
||||
String payload = gson.toJson(actionPayload);
|
||||
return createLevelAction(level, server, action, user, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LevelAction> getLevelActionsOfUserInServer(AUserExperience aUserInAServer) {
|
||||
return levelActionRepository.findByServerAndAffectedUserIsNullOrServerAndAffectedUser(aUserInAServer.getServer(),
|
||||
aUserInAServer.getServer(), aUserInAServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LevelAction> getLevelActionsOfServer(AServer server) {
|
||||
return levelActionRepository.findByServer(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<LevelAction> getLevelAction(String action, Integer level, AServer server, AUserExperience aUserExperience) {
|
||||
AExperienceLevel experienceLevel = experienceLevelManagementService.getLevel(level);
|
||||
return levelActionRepository.findByServerAndActionAndLevelOrAffectedUserAndLevelAndAction(server, action.toLowerCase(),
|
||||
experienceLevel, aUserExperience, experienceLevel, action.toLowerCase());
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,9 @@ import dev.sheldan.abstracto.experience.model.database.LeaderBoardEntryResult;
|
||||
import dev.sheldan.abstracto.experience.repository.UserExperienceRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
@@ -70,6 +72,11 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
|
||||
return repository.findByUser_ServerReference(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<AUserExperience> loadAllUsersPaginated(AServer server, Pageable pageable) {
|
||||
return repository.findAllByServer(server, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AUserExperience> findLeaderBoardUsersPaginated(AServer aServer, Integer page, Integer size) {
|
||||
return repository.findTop10ByUser_ServerReferenceOrderByExperienceDesc(aServer, PageRequest.of(page, size));
|
||||
|
||||
@@ -13,4 +13,10 @@ abstracto.systemConfigs.expCooldownSeconds.longValue=60
|
||||
|
||||
abstracto.featureModes.levelUpNotification.featureName=experience
|
||||
abstracto.featureModes.levelUpNotification.mode=levelUpNotification
|
||||
abstracto.featureModes.levelUpNotification.enabled=false
|
||||
abstracto.featureModes.levelUpNotification.enabled=false
|
||||
|
||||
abstracto.featureModes.levelAction.featureName=experience
|
||||
abstracto.featureModes.levelAction.mode=levelAction
|
||||
abstracto.featureModes.levelAction.enabled=false
|
||||
|
||||
abstracto.experience.leaderboard.externalUrl=${FRONTEND_BASE:}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<property name="experienceModule" value="(SELECT id FROM module WHERE name = 'experience')"/>
|
||||
<property name="experienceFeature" value="(SELECT id FROM feature WHERE key = 'experience')"/>
|
||||
<changeSet author="Sheldan" id="experience-levelAction-commands">
|
||||
<insert tableName="command">
|
||||
<column name="name" value="addLevelAction"/>
|
||||
<column name="module_id" valueComputed="${experienceModule}"/>
|
||||
<column name="feature_id" valueComputed="${experienceFeature}"/>
|
||||
</insert>
|
||||
<insert tableName="command">
|
||||
<column name="name" value="removeLevelAction"/>
|
||||
<column name="module_id" valueComputed="${experienceModule}"/>
|
||||
<column name="feature_id" valueComputed="${experienceFeature}"/>
|
||||
</insert>
|
||||
<insert tableName="command">
|
||||
<column name="name" value="showLevelActions"/>
|
||||
<column name="module_id" valueComputed="${experienceModule}"/>
|
||||
<column name="feature_id" valueComputed="${experienceFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<include file="command.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
<changeSet author="Sheldan" id="level_action-table">
|
||||
<createTable tableName="level_action">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="pk_level_action"/>
|
||||
</column>
|
||||
<column name="action" type="VARCHAR(128)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="payload" type="TEXT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="affected_user_id" type="BIGINT">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
|
||||
<column name="level_id" type="INTEGER">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<addForeignKeyConstraint baseColumnNames="level_id" baseTableName="level_action" constraintName="fk_level_action_level" deferrable="false"
|
||||
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="level"
|
||||
referencedTableName="experience_level" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="affected_user_id" baseTableName="level_action" constraintName="fk_level_action_user" deferrable="false"
|
||||
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id"
|
||||
referencedTableName="user_experience" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="level_action" constraintName="fk_level_action_server" deferrable="false"
|
||||
initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server"
|
||||
validate="true"/>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS level_action_update_trigger ON level_action;
|
||||
CREATE TRIGGER level_action_update_trigger BEFORE UPDATE ON level_action FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS level_action_insert_trigger ON level_action;
|
||||
CREATE TRIGGER level_action_insert_trigger BEFORE INSERT ON level_action FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.26.xsd" >
|
||||
|
||||
<include file="level_action.xml" relativeToChangelogFile="true"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -6,4 +6,5 @@
|
||||
<include file="1.2.15/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.8/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.17/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.5.26/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,84 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AddRoleLevelActionTest {
|
||||
@InjectMocks
|
||||
private AddRoleLevelAction action;
|
||||
|
||||
@Mock
|
||||
private AUserExperience exp;
|
||||
|
||||
@Mock
|
||||
private LevelAction levelAction;
|
||||
|
||||
@Mock
|
||||
private AExperienceLevel level;
|
||||
|
||||
private final Integer LOW_LEVEL = 1;
|
||||
private final Integer MID_LEVEL = 2;
|
||||
private final Integer HIGH_LEVEL = 3;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(levelAction.getLevel()).thenReturn(level);
|
||||
}
|
||||
|
||||
@Test // rejoin too low case
|
||||
public void noLevelChangeActionNotReached() {
|
||||
executeTest(LOW_LEVEL, LOW_LEVEL, HIGH_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // re-join exact case
|
||||
public void noLevelChangeActionReached() {
|
||||
executeTest(LOW_LEVEL, LOW_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // normal leveling, higher action
|
||||
public void levelChangeActionNotReached() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, HIGH_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // normal leveling
|
||||
public void levelChangeActionReached() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, MID_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // a case for this is a large experience jump
|
||||
public void levelChangeActionOverJumped() {
|
||||
executeTest(LOW_LEVEL, HIGH_LEVEL, MID_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // a case for this is a re-join
|
||||
public void noLevelChangeActionOverJumped() {
|
||||
executeTest(HIGH_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // we dont want to re-execute previous actions (previous = lower level)
|
||||
public void levelChangeActionEqualsPrevious() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // we dont want to re-execute previous actions (previous = way lower level)
|
||||
public void levelChangeActionBelow() {
|
||||
executeTest(MID_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
private void executeTest(Integer oldLevel, Integer currentLevel, Integer actionLevel, boolean expected) {
|
||||
when(exp.getLevelOrDefault()).thenReturn(currentLevel);
|
||||
when(level.getLevel()).thenReturn(actionLevel);
|
||||
Assertions.assertThat(action.shouldExecute(exp, oldLevel, levelAction)).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RemoveMemberFromChannelLevelActionTest {
|
||||
|
||||
@InjectMocks
|
||||
private SendMessageToChannelLevelAction action;
|
||||
|
||||
@Mock
|
||||
private AUserExperience exp;
|
||||
|
||||
@Mock
|
||||
private LevelAction levelAction;
|
||||
|
||||
@Mock
|
||||
private AExperienceLevel level;
|
||||
|
||||
private final Integer LOW_LEVEL = 1;
|
||||
private final Integer MID_LEVEL = 2;
|
||||
private final Integer HIGH_LEVEL = 3;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
when(levelAction.getLevel()).thenReturn(level);
|
||||
}
|
||||
|
||||
@Test // rejoin too low case
|
||||
public void noLevelChangeActionNotReached() {
|
||||
executeTest(LOW_LEVEL, LOW_LEVEL, HIGH_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // re-join exact case
|
||||
public void noLevelChangeActionReached() {
|
||||
executeTest(LOW_LEVEL, LOW_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // normal leveling, higher action
|
||||
public void levelChangeActionNotReached() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, HIGH_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // normal leveling
|
||||
public void levelChangeActionReached() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, MID_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // a case for this is a large experience jump
|
||||
public void levelChangeActionOverJumped() {
|
||||
executeTest(LOW_LEVEL, HIGH_LEVEL, MID_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // a case for this is a re-join
|
||||
public void noLevelChangeActionOverJumped() {
|
||||
executeTest(HIGH_LEVEL, HIGH_LEVEL, LOW_LEVEL, true);
|
||||
}
|
||||
|
||||
@Test // we dont want to re-execute previous actions (previous = lower level)
|
||||
public void levelChangeActionEqualsPrevious() {
|
||||
executeTest(LOW_LEVEL, MID_LEVEL, LOW_LEVEL, false);
|
||||
}
|
||||
|
||||
@Test // we dont want to re-execute previous actions (previous = way lower level)
|
||||
public void levelChangeActionBelow() {
|
||||
executeTest(MID_LEVEL, HIGH_LEVEL, LOW_LEVEL, false);
|
||||
}
|
||||
|
||||
private void executeTest(Integer oldLevel, Integer currentLevel, Integer actionLevel, boolean expected) {
|
||||
when(exp.getLevelOrDefault()).thenReturn(currentLevel);
|
||||
when(level.getLevel()).thenReturn(actionLevel);
|
||||
Assertions.assertThat(action.shouldExecute(exp, oldLevel, levelAction)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>experience-tracking</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.springframework.stereotype.Component;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static dev.sheldan.abstracto.experience.config.ExperienceFeatureMode.LEVEL_ACTION;
|
||||
import static dev.sheldan.abstracto.experience.config.ExperienceFeatureMode.LEVEL_UP_NOTIFICATION;
|
||||
|
||||
/**
|
||||
@@ -46,6 +47,6 @@ public class ExperienceFeatureConfig implements FeatureConfig {
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getAvailableModes() {
|
||||
return Arrays.asList(LEVEL_UP_NOTIFICATION);
|
||||
return Arrays.asList(LEVEL_UP_NOTIFICATION, LEVEL_ACTION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum ExperienceFeatureMode implements FeatureMode {
|
||||
LEVEL_UP_NOTIFICATION("levelUpNotification");
|
||||
LEVEL_UP_NOTIFICATION("levelUpNotification"),
|
||||
LEVEL_ACTION("levelAction");
|
||||
|
||||
private final String key;
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package dev.sheldan.abstracto.experience.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.templating.Templatable;
|
||||
|
||||
public class LevelActionAlreadyExistsException extends AbstractoRunTimeException implements Templatable {
|
||||
|
||||
public LevelActionAlreadyExistsException() {
|
||||
super("Level action already exists.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "level_action_already_exists_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package dev.sheldan.abstracto.experience.exception;
|
||||
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.templating.Templatable;
|
||||
|
||||
public class LevelActionNotFoundException extends AbstractoRunTimeException implements Templatable {
|
||||
|
||||
public LevelActionNotFoundException() {
|
||||
super("Level action not found.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "level_action_not_found_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTemplateModel() {
|
||||
return new Object();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import dev.sheldan.abstracto.experience.model.LevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
|
||||
public interface LevelActionListener {
|
||||
String getName();
|
||||
|
||||
void apply(AUserExperience userExperience, LevelAction levelAction, MemberActionModification container);
|
||||
|
||||
boolean shouldExecute(AUserExperience aUserExperience, Integer oldLevel, LevelAction levelAction);
|
||||
|
||||
void prepareAction(LevelAction levelAction);
|
||||
|
||||
|
||||
LevelActionPayload createPayload(Guild guild, String input);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package dev.sheldan.abstracto.experience.listener;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class MemberActionModification {
|
||||
@Builder.Default
|
||||
private Set<Long> rolesToRemove = new HashSet<>();
|
||||
|
||||
@Builder.Default
|
||||
private Set<Long> rolesToAdd = new HashSet<>();
|
||||
|
||||
@Builder.Default
|
||||
private Set<Long> channelsToRemove = new HashSet<>();
|
||||
|
||||
@Builder.Default
|
||||
private Set<Long> channelsToAdd = new HashSet<>();
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package dev.sheldan.abstracto.experience.model;
|
||||
|
||||
public interface LevelActionPayload {
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package dev.sheldan.abstracto.experience.model.database;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.experience.model.LevelActionPayload;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Builder
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Table(name = "level_action")
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode
|
||||
public class LevelAction {
|
||||
|
||||
@Id
|
||||
@Column(name = "id", nullable = false)
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "level_id", nullable = false)
|
||||
private AExperienceLevel level;
|
||||
|
||||
@Column(name = "action", nullable = false)
|
||||
private String action;
|
||||
|
||||
@Column(name = "payload", nullable = false)
|
||||
private String payload;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "affected_user_id")
|
||||
private AUserExperience affectedUser;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "server_id", nullable = false)
|
||||
private AServer server;
|
||||
|
||||
@Column(name = "created", nullable = false, insertable = false, updatable = false)
|
||||
private Instant created;
|
||||
|
||||
@Column(name = "updated", insertable = false, updatable = false)
|
||||
private Instant updated;
|
||||
|
||||
@Builder.Default
|
||||
@Transient
|
||||
private LevelActionPayload loadedPayload = null;
|
||||
|
||||
}
|
||||
@@ -24,4 +24,5 @@ public class LeaderBoardModel extends SlimUserInitiatedServerContext {
|
||||
* The {@link LeaderBoardEntryModel} containing the leaderboard information executing the command.
|
||||
*/
|
||||
private LeaderBoardEntryModel userExecuting;
|
||||
private String leaderboardUrl;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package dev.sheldan.abstracto.experience.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.template.display.MemberDisplay;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class LevelActionDisplay {
|
||||
private String actionKey;
|
||||
private Integer level;
|
||||
private MemberDisplay member;
|
||||
private String parameters;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.abstracto.experience.model.template;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class LevelActionsDisplay {
|
||||
private List<LevelActionDisplay> actions;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.sheldan.abstracto.experience.service;
|
||||
|
||||
import dev.sheldan.abstracto.experience.listener.LevelActionListener;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
import dev.sheldan.abstracto.experience.model.template.LevelActionsDisplay;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface LevelActionService {
|
||||
CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user);
|
||||
CompletableFuture<Void> applyLevelActionsToUser(AUserExperience user, Integer oldLevel);
|
||||
List<String> getAvailableLevelActions();
|
||||
Optional<LevelActionListener> getLevelActionListenerForName(String name);
|
||||
|
||||
Optional<LevelAction> getLevelAction(AUserExperience userExperience, String action, Integer level);
|
||||
|
||||
LevelActionsDisplay getLevelActionsToDisplay(Guild guild);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package dev.sheldan.abstracto.experience.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.experience.model.LevelActionPayload;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LevelAction;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface LevelActionManagementService {
|
||||
LevelAction createLevelAction(Integer level, AServer server, String action, AUserExperience user, String parameters);
|
||||
void deleteLevelAction(Integer level, AServer server, String action, AUserExperience user);
|
||||
LevelAction createLevelAction(Integer level, AServer server, String action, AUserExperience user, LevelActionPayload actionPayload);
|
||||
|
||||
List<LevelAction> getLevelActionsOfUserInServer(AUserExperience aUserInAServer);
|
||||
List<LevelAction> getLevelActionsOfServer(AServer server);
|
||||
|
||||
Optional<LevelAction> getLevelAction(String action, Integer level, AServer server, AUserExperience aUserExperience);
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.experience.model.database.AExperienceRole;
|
||||
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
|
||||
import dev.sheldan.abstracto.experience.model.database.LeaderBoardEntryResult;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -50,6 +52,7 @@ public interface UserExperienceManagementService {
|
||||
* @return A list of {@link AUserExperience} objects associated with the given {@link AServer}
|
||||
*/
|
||||
List<AUserExperience> loadAllUsers(AServer server);
|
||||
Page<AUserExperience> loadAllUsersPaginated(AServer server, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Retrieves a list of {@link AUserExperience} ordered by {@link AUserExperience} experience and only returns the positions between {@code start} and @{code end}.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>giveaway</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>giveaway-impl</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>giveaway</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>giveaway-int</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>giveaway</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>image-generation</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>image-generation-impl</artifactId>
|
||||
|
||||
@@ -2,11 +2,13 @@ package dev.sheldan.abstracto.imagegeneration.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CombinedParameterEntry;
|
||||
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.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;
|
||||
@@ -21,16 +23,18 @@ import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationFeatureDefini
|
||||
import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationSlashCommandNames;
|
||||
import dev.sheldan.abstracto.imagegeneration.service.ImageGenerationService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static dev.sheldan.abstracto.core.command.config.Parameter.ADDITIONAL_TYPES_KEY;
|
||||
|
||||
@Component
|
||||
public class Bonk extends AbstractConditionableCommand {
|
||||
public static final String MEMBER_PARAMETER_KEY = "member";
|
||||
@@ -65,7 +69,11 @@ public class Bonk extends AbstractConditionableCommand {
|
||||
if(parameters.isEmpty()) {
|
||||
member = commandContext.getAuthor();
|
||||
} else {
|
||||
member = (Member) parameters.get(0);
|
||||
if(parameters.get(0) instanceof Message) {
|
||||
member = ((Message) parameters.get(0)).getMember();
|
||||
} else {
|
||||
member = (Member) parameters.get(0);
|
||||
}
|
||||
}
|
||||
File bonkGifFile = imageGenerationService.getBonkGif(member.getEffectiveAvatar().getUrl(imageSize));
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object());
|
||||
@@ -107,10 +115,13 @@ public class Bonk extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
Map<String, Object> parameterAlternatives = new HashMap<>();
|
||||
parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(CombinedParameterEntry.messageParameter(Message.class), CombinedParameterEntry.parameter(Member.class)));
|
||||
Parameter memberParameter = Parameter
|
||||
.builder()
|
||||
.name(MEMBER_PARAMETER_KEY)
|
||||
.type(Member.class)
|
||||
.type(CombinedParameter.class)
|
||||
.additionalInfo(parameterAlternatives)
|
||||
.templated(true)
|
||||
.optional(true)
|
||||
.build();
|
||||
|
||||
@@ -2,11 +2,13 @@ package dev.sheldan.abstracto.imagegeneration.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CombinedParameterEntry;
|
||||
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.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;
|
||||
@@ -21,16 +23,18 @@ import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationFeatureDefini
|
||||
import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationSlashCommandNames;
|
||||
import dev.sheldan.abstracto.imagegeneration.service.ImageGenerationService;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static dev.sheldan.abstracto.core.command.config.Parameter.ADDITIONAL_TYPES_KEY;
|
||||
|
||||
@Component
|
||||
public class Pat extends AbstractConditionableCommand {
|
||||
public static final String MEMBER_PARAMETER_KEY = "member";
|
||||
@@ -65,7 +69,11 @@ public class Pat extends AbstractConditionableCommand {
|
||||
if(parameters.isEmpty()) {
|
||||
member = commandContext.getAuthor();
|
||||
} else {
|
||||
member = (Member) parameters.get(0);
|
||||
if(parameters.get(0) instanceof Message) {
|
||||
member = ((Message) parameters.get(0)).getMember();
|
||||
} else {
|
||||
member = (Member) parameters.get(0);
|
||||
}
|
||||
}
|
||||
File patGifFile = imageGenerationService.getPatGif(member.getEffectiveAvatar().getUrl(imageSize));
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(PAT_EMBED_TEMPLATE_KEY, new Object());
|
||||
@@ -107,10 +115,13 @@ public class Pat extends AbstractConditionableCommand {
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
Map<String, Object> parameterAlternatives = new HashMap<>();
|
||||
parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(CombinedParameterEntry.messageParameter(Message.class), CombinedParameterEntry.parameter(Member.class)));
|
||||
Parameter memberParameter = Parameter
|
||||
.builder()
|
||||
.name(MEMBER_PARAMETER_KEY)
|
||||
.type(Member.class)
|
||||
.type(CombinedParameter.class)
|
||||
.additionalInfo(parameterAlternatives)
|
||||
.templated(true)
|
||||
.optional(true)
|
||||
.build();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>image-generation</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>image-generation-int</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>image-generation</artifactId>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>invite-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ import dev.sheldan.abstracto.invitefilter.model.template.listener.DeletedInvite;
|
||||
import dev.sheldan.abstracto.invitefilter.model.template.listener.DeletedInvitesNotificationModel;
|
||||
import dev.sheldan.abstracto.invitefilter.service.management.AllowedInviteLinkManagement;
|
||||
import dev.sheldan.abstracto.invitefilter.service.management.FilteredInviteLinkManagement;
|
||||
import dev.sheldan.abstracto.moderation.model.ModerationActionButton;
|
||||
import dev.sheldan.abstracto.moderation.service.ModerationActionService;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -78,6 +80,9 @@ public class InviteLinkFilterServiceBean implements InviteLinkFilterService {
|
||||
@Autowired
|
||||
private RoleImmunityService roleImmunityService;
|
||||
|
||||
@Autowired(required = false)
|
||||
private ModerationActionService moderationActionService;
|
||||
|
||||
private static final Pattern INVITE_CODE_PATTERN = Pattern.compile("(?<code>[a-z0-9-]+)", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
public static final String INVITE_FILTER_METRIC = "invite.filter";
|
||||
@@ -230,10 +235,18 @@ public class InviteLinkFilterServiceBean implements InviteLinkFilterService {
|
||||
log.info("Post target {} not defined for server {} - not sending invite link deletion notification.", InviteFilterPostTarget.INVITE_DELETE_LOG.getKey(), serverId);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
boolean moderationActionsEnabled = featureModeService.featureModeActive(InviteFilterFeatureDefinition.INVITE_FILTER, serverId, InviteFilterMode.FILTER_MODERATION_ACTIONS);
|
||||
List<ModerationActionButton> moderationActionComponents = new ArrayList<>();
|
||||
if(moderationActionsEnabled && moderationActionService != null) {
|
||||
ServerUser reportedServerUser = ServerUser.fromMember(message.getMember());
|
||||
List<ModerationActionButton> moderationActions = moderationActionService.getModerationActionButtons(reportedServerUser);
|
||||
moderationActionComponents.addAll(moderationActions);
|
||||
}
|
||||
DeletedInvitesNotificationModel model = DeletedInvitesNotificationModel
|
||||
.builder()
|
||||
.author(message.getMember())
|
||||
.guild(message.getGuild())
|
||||
.moderationActionComponents(moderationActionComponents)
|
||||
.message(message)
|
||||
.channel(message.getChannel())
|
||||
.invites(groupInvites(codes))
|
||||
|
||||
@@ -11,3 +11,6 @@ abstracto.featureModes.filterNotifications.featureName=inviteFilter
|
||||
abstracto.featureModes.filterNotifications.mode=filterNotifications
|
||||
abstracto.featureModes.filterNotifications.enabled=true
|
||||
|
||||
abstracto.featureModes.filterModerationActions.featureName=inviteFilter
|
||||
abstracto.featureModes.filterModerationActions.mode=filterModerationActions
|
||||
abstracto.featureModes.filterModerationActions.enabled=false
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>invite-filter</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
<artifactId>core-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<artifactId>moderation-int</artifactId>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -23,6 +23,6 @@ public class InviteFilterFeatureConfig implements FeatureConfig {
|
||||
|
||||
@Override
|
||||
public List<FeatureMode> getAvailableModes() {
|
||||
return Arrays.asList(InviteFilterMode.FILTER_NOTIFICATIONS, InviteFilterMode.TRACK_USES);
|
||||
return Arrays.asList(InviteFilterMode.values());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum InviteFilterMode implements FeatureMode {
|
||||
TRACK_USES("trackUses"), FILTER_NOTIFICATIONS("filterNotifications");
|
||||
TRACK_USES("trackUses"), FILTER_NOTIFICATIONS("filterNotifications"), FILTER_MODERATION_ACTIONS("filterModerationActions");
|
||||
|
||||
private final String key;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package dev.sheldan.abstracto.invitefilter.model.template.listener;
|
||||
|
||||
import dev.sheldan.abstracto.moderation.model.ModerationActionButton;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -17,4 +18,5 @@ public class DeletedInvitesNotificationModel {
|
||||
private Member author;
|
||||
private Message message;
|
||||
private List<DeletedInvite> invites;
|
||||
private List<ModerationActionButton> moderationActionComponents;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>link-embed</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>link-embed</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>abstracto-modules</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>logging</artifactId>
|
||||
<groupId>dev.sheldan.abstracto.modules</groupId>
|
||||
<version>1.5.25</version>
|
||||
<version>1.5.50-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user