Compare commits
33
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87f78ccbea | ||
|
|
5ab18ff5ce | ||
|
|
e0e9bbff10 | ||
|
|
d0c06cd6bf | ||
|
|
e58854a85c | ||
|
|
e0612f90a8 | ||
|
|
4b88be0517 | ||
|
|
8fec0271cc | ||
|
|
88d954427a | ||
|
|
febd12f2f2 | ||
|
|
ffb393706b | ||
|
|
c021f84415 | ||
|
|
da3142df0c | ||
|
|
15d58bba38 | ||
|
|
247f217e2e | ||
|
|
c98d47b5ca | ||
|
|
81e15a5394 | ||
|
|
ddd7d119bb | ||
|
|
ccf56298d8 | ||
|
|
4fa790259e | ||
|
|
aa587ddf3c | ||
|
|
f8ebe28cb4 | ||
|
|
1544cda9d2 | ||
|
|
52bb9c026b | ||
|
|
ad77cf630e | ||
|
|
62fc2097c2 | ||
|
|
b96e5b2880 | ||
|
|
b3bd6a45fe | ||
|
|
83e618c6a3 | ||
|
|
078c540327 | ||
|
|
e021a713b2 | ||
|
|
91aaafeb40 | ||
|
|
99457b40fc |
No files matched your search
+1
-1
@@ -1,5 +1,5 @@
|
||||
.git
|
||||
.gitea
|
||||
.github
|
||||
.idea
|
||||
.mvn
|
||||
src
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
env:
|
||||
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=${{ github.workspace }}/.m2/repository -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
|
||||
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version --no-transfer-progress -DinstallAtEnd=true -DdeployAtEnd=true"
|
||||
# Docker image name; expects REGISTRY_URL like registry.example.com
|
||||
CI_REGISTRY_IMAGE: "${{ secrets.REGISTRY_URL }}/${{ github.repository }}"
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
name: Compile
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
|
||||
- name: Cache Maven local repo and wrapper
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/.m2/repository
|
||||
.mvn
|
||||
key: m2-${{ runner.os }}-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
m2-${{ runner.os }}-
|
||||
|
||||
- name: Compile
|
||||
run: |
|
||||
chmod +x ./mvnw
|
||||
./mvnw $MAVEN_CLI_OPTS compile
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
needs: compile
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
|
||||
- name: Cache Maven local repo and wrapper
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/.m2/repository
|
||||
.mvn
|
||||
key: m2-${{ runner.os }}-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
m2-${{ runner.os }}-
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
chmod +x ./mvnw
|
||||
./mvnw $MAVEN_CLI_OPTS test
|
||||
|
||||
- name: Upload test reports (artifact)
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: junit-reports
|
||||
path: |
|
||||
**/target/*-reports/TEST-*.xml
|
||||
if-no-files-found: ignore
|
||||
|
||||
package:
|
||||
name: Package
|
||||
runs-on: ubuntu-latest
|
||||
needs: test
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
|
||||
- name: Cache Maven local repo and wrapper
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/.m2/repository
|
||||
.mvn
|
||||
key: m2-${{ runner.os }}-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
m2-${{ runner.os }}-
|
||||
|
||||
- name: Build package (skip tests)
|
||||
run: |
|
||||
chmod +x ./mvnw
|
||||
./mvnw $MAVEN_CLI_OPTS package -DskipTests=true
|
||||
|
||||
- name: Upload Maven artifacts
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: maven-artifacts
|
||||
path: |
|
||||
target/netneutrality.jar
|
||||
startup.sh
|
||||
if-no-files-found: error
|
||||
|
||||
docker-main:
|
||||
name: Docker Build and Push (main)
|
||||
runs-on: ubuntu-latest
|
||||
needs: package
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: maven-artifacts
|
||||
path: .
|
||||
|
||||
- name: Log in to registry
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ secrets.REGISTRY_URL }}
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Build and push (main)
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: "${{ secrets.REGISTRY_URL }}/${{ secrets.REGISTRY_USER }}/netneutrality:main"
|
||||
|
||||
docker-release:
|
||||
name: Docker Build and Push (release)
|
||||
runs-on: ubuntu-latest
|
||||
needs: package
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: maven-artifacts
|
||||
path: .
|
||||
|
||||
- name: Compute release version
|
||||
id: rel
|
||||
shell: bash
|
||||
run: |
|
||||
# Strip leading 'v' if present (e.g., v1.2.3 -> 1.2.3)
|
||||
ver="${GITHUB_REF_NAME#v}"
|
||||
echo "version=$ver" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Log in to registry
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ secrets.REGISTRY_URL }}
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Build and push (release + latest)
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.REGISTRY_URL }}/${{ secrets.REGISTRY_USER }}/netneutrality:${{ steps.rel.outputs.version }}
|
||||
${{ secrets.REGISTRY_URL }}/${{ secrets.REGISTRY_USER }}/netneutrality:latest
|
||||
@@ -0,0 +1,125 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
jobs:
|
||||
package:
|
||||
name: Package
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Set up JDK
|
||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
|
||||
- name: Build package
|
||||
run: |
|
||||
chmod +x ./mvnw
|
||||
./mvnw --batch-mode --update-snapshots verify
|
||||
|
||||
- name: Upload test reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@c6a366c94c3e0affe28c06c8df20a878f24da3cf # v3
|
||||
with:
|
||||
name: junit-reports
|
||||
path: |
|
||||
**/target/*-reports/TEST-*.xml
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Upload Maven artifacts
|
||||
uses: actions/upload-artifact@c6a366c94c3e0affe28c06c8df20a878f24da3cf # v3
|
||||
with:
|
||||
name: maven-artifacts
|
||||
path: |
|
||||
target/netneutrality.jar
|
||||
startup.sh
|
||||
if-no-files-found: error
|
||||
|
||||
docker-main:
|
||||
name: Docker Build and Push (main)
|
||||
runs-on: ubuntu-latest
|
||||
needs: package
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@a9bc5e6ef2cb54c177f32aa5726adaa15e7e2d59 # v3
|
||||
with:
|
||||
name: maven-artifacts
|
||||
path: .
|
||||
|
||||
- name: Log in to registry
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
||||
with:
|
||||
registry: ${{ secrets.REGISTRY_URL }}
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Build and push (main)
|
||||
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: "${{ secrets.REGISTRY_URL }}/${{ secrets.REGISTRY_USER }}/netneutrality:main"
|
||||
|
||||
docker-release:
|
||||
name: Docker Build and Push (release)
|
||||
runs-on: ubuntu-latest
|
||||
needs: package
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@a9bc5e6ef2cb54c177f32aa5726adaa15e7e2d59 # v3
|
||||
with:
|
||||
name: maven-artifacts
|
||||
path: .
|
||||
|
||||
- name: Compute release version
|
||||
id: rel
|
||||
shell: bash
|
||||
run: |
|
||||
# Strip leading 'v' if present (e.g., v1.2.3 -> 1.2.3)
|
||||
ver="${GITHUB_REF_NAME#v}"
|
||||
echo "version=$ver" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Log in to registry
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
||||
with:
|
||||
registry: ${{ secrets.REGISTRY_URL }}
|
||||
username: ${{ secrets.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Build and push (release + latest)
|
||||
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
${{ secrets.REGISTRY_URL }}/${{ secrets.REGISTRY_USER }}/netneutrality:${{ steps.rel.outputs.version }}
|
||||
${{ secrets.REGISTRY_URL }}/${{ secrets.REGISTRY_USER }}/netneutrality:latest
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
wrapperVersion=3.3.4
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.15/apache-maven-3.9.15-bin.zip
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM eclipse-temurin:25-jre
|
||||
FROM eclipse-temurin:25-jre@sha256:ff82c74a630c08b417502c4c18189e62074edbb28eb1f2d31b799ac138c01058
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends netcat-openbsd curl && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>25</maven.compiler.source>
|
||||
<maven.compiler.target>25</maven.compiler.target>
|
||||
<mockito.version>5.20.0</mockito.version>
|
||||
<mockito.version>5.23.0</mockito.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -42,7 +42,7 @@
|
||||
<plugin>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-maven-plugin</artifactId>
|
||||
<version>11.14.1</version>
|
||||
<version>11.20.3</version>
|
||||
<configuration>
|
||||
<url>${env.FLYWAY_URL}</url>
|
||||
<user>${env.FLYWAY_USER}</user>
|
||||
@@ -52,7 +52,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<propertiesEncoding>UTF-8</propertiesEncoding>
|
||||
</configuration>
|
||||
@@ -73,7 +73,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
@@ -144,7 +144,7 @@
|
||||
<dependency>
|
||||
<groupId>net.dv8tion</groupId>
|
||||
<artifactId>JDA</artifactId>
|
||||
<version>6.3.1</version>
|
||||
<version>6.4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dev.arbjerg</groupId>
|
||||
@@ -154,33 +154,33 @@
|
||||
<dependency>
|
||||
<groupId>dev.lavalink.youtube</groupId>
|
||||
<artifactId>v2</artifactId>
|
||||
<version>1.18.0</version>
|
||||
<version>1.18.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>club.minnced</groupId>
|
||||
<artifactId>jdave-api</artifactId>
|
||||
<version>0.1.7</version>
|
||||
<version>0.1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>club.minnced</groupId>
|
||||
<artifactId>jdave-native-linux-x86-64</artifactId>
|
||||
<version>0.1.7</version>
|
||||
<version>0.1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>club.minnced</groupId>
|
||||
<artifactId>jdave-native-win-x86-64</artifactId>
|
||||
<version>0.1.7</version>
|
||||
<version>0.1.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>club.minnced</groupId>
|
||||
<artifactId>jdave-native-darwin</artifactId>
|
||||
<version>0.1.7</version>
|
||||
<version>0.1.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp-jvm</artifactId>
|
||||
<version>5.3.0</version>
|
||||
<version>5.3.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -196,24 +196,24 @@
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>9.5.0</version>
|
||||
<version>9.7.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
<version>11.14.1</version>
|
||||
<version>11.20.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-mysql</artifactId>
|
||||
<version>11.14.1</version>
|
||||
<version>11.20.3</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.sentry</groupId>
|
||||
<artifactId>sentry</artifactId>
|
||||
<version>8.25.0</version>
|
||||
<version>8.41.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.gitlab4j</groupId>
|
||||
@@ -224,7 +224,12 @@
|
||||
<dependency>
|
||||
<groupId>net.fellbaum</groupId>
|
||||
<artifactId>jemoji</artifactId>
|
||||
<version>1.7.5</version>
|
||||
<version>1.7.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.fellbaum</groupId>
|
||||
<artifactId>jemoji</artifactId>
|
||||
<version>1.7.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -235,7 +240,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.13.2</version>
|
||||
<version>2.14.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -247,17 +252,17 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.25.3</version>
|
||||
<version>2.26.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.25.3</version>
|
||||
<version>2.26.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
<version>2.25.3</version>
|
||||
<version>2.26.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -274,7 +279,7 @@
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>6.0.1</version>
|
||||
<version>6.0.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+35
-8
@@ -6,12 +6,6 @@
|
||||
"group:flyway"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchPackageNames": [
|
||||
"quay.io/buildah/stable"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"matchPackageNames": [
|
||||
"mariadb"
|
||||
@@ -19,18 +13,51 @@
|
||||
"automerge": false,
|
||||
"dependencyDashboardApproval": true
|
||||
},
|
||||
{
|
||||
"matchManagers": ["maven"],
|
||||
"extends": ["schedule:monthly"]
|
||||
},
|
||||
{
|
||||
"groupName": "maven plugins",
|
||||
"matchManagers": ["maven"],
|
||||
"matchDepTypes": ["plugin"],
|
||||
"extends": ["schedule:weekly"]
|
||||
},
|
||||
{
|
||||
"groupName": "hibernate orm",
|
||||
"matchPackageNames": [
|
||||
"org.hibernate.orm:**"
|
||||
]
|
||||
],
|
||||
"extends": ["schedule:monthly"]
|
||||
},
|
||||
{
|
||||
"groupName": "apache commons",
|
||||
"matchPackageNames": [
|
||||
"commons-**",
|
||||
"org.apache.commons:**"
|
||||
]
|
||||
],
|
||||
"extends": ["schedule:monthly"]
|
||||
},
|
||||
{
|
||||
"matchManagers": ["maven"],
|
||||
"matchDepTypes": ["dependency", "parentPom"],
|
||||
"matchPackageNames": [
|
||||
"net.dv8tion:JDA",
|
||||
"dev.arbjerg:lavaplayer",
|
||||
"dev.lavalink.youtube:**",
|
||||
"club.minnced:jdave-*"
|
||||
],
|
||||
"schedule": ["at any time"]
|
||||
},
|
||||
{
|
||||
"groupName": "github actions (minor/patch)",
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchUpdateTypes": ["minor", "patch", "digest"]
|
||||
},
|
||||
{
|
||||
"groupName": "github actions (major)",
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchUpdateTypes": ["major"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public class NetNeutrality {
|
||||
options.setEnvironment(env);
|
||||
options.setTracesSampleRate(1.0);
|
||||
options.setDebug(false);
|
||||
options.setRelease(VERSION);
|
||||
options.setRelease(Settings.getVersion());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,11 @@ public class MusicChannelContext extends AbstractContext implements NoMessageCon
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFromGuild() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteMessage() {
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package me.bobert.netneutrality.core.command;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
public abstract class AbstractAdminCommand extends AbstractCommand {
|
||||
|
||||
@Override
|
||||
public boolean needAdmin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandCategory getCategory() {
|
||||
return CommandCategory.ADMINISTRATION;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package me.bobert.netneutrality.core.command;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.context.command.MessageMenuContext;
|
||||
import me.bobert.netneutrality.core.command.options.CommandOptionsBuilder;
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
public abstract class AbstractMessageMenuCommand extends AbstractCommand {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGuildOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSlashCommandOnly() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommandOptions(CommandOptionsBuilder builder) {
|
||||
// no options for context commands
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandCategory getCategory() {
|
||||
return CommandCategory.UNLISTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.MESSAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandExecutionResult execute(CommandContext context) {
|
||||
if (context instanceof MessageMenuContext mc) {
|
||||
Message message = mc.getTarget();
|
||||
return execute(message, context);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Wrong context type for this command");
|
||||
}
|
||||
|
||||
public abstract CommandExecutionResult execute(Message target, CommandContext context);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package me.bobert.netneutrality.core.command;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.context.command.UserMenuContext;
|
||||
import me.bobert.netneutrality.core.command.options.CommandOptionsBuilder;
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
public abstract class AbstractUserMenuCommand extends AbstractCommand {
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSlashCommandOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommandOptions(CommandOptionsBuilder builder) {
|
||||
// no options for context commands
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return Type.USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandExecutionResult execute(CommandContext context) {
|
||||
if (context instanceof UserMenuContext uc) {
|
||||
User user = uc.getTarget();
|
||||
return execute(user, context);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Wrong context type for this command");
|
||||
}
|
||||
|
||||
public abstract CommandExecutionResult execute(User target, CommandContext context);
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
<<<<<<<< HEAD:src/main/java/me/bobert/netneutrality/core/command/impl/AbstractCommand.java
|
||||
package me.bobert.netneutrality.core.command.impl;
|
||||
========
|
||||
package me.bobert.netneutrality.core.command;
|
||||
>>>>>>>> 8479f71 (change package of core command classes so it makes more sense and rename getType() to getCategory() in command interface):src/main/java/me/bobert/netneutrality/core/command/AbstractCommand.java
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<<<<<<<< HEAD:src/main/java/me/bobert/netneutrality/core/command/impl/MusicCommand.java
|
||||
package me.bobert.netneutrality.core.command.impl;
|
||||
========
|
||||
package me.bobert.netneutrality.core.command;
|
||||
>>>>>>>> 8479f71 (change package of core command classes so it makes more sense and rename getType() to getCategory() in command interface):src/main/java/me/bobert/netneutrality/core/command/AbstractMusicCommand.java
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
package me.bobert.netneutrality.core.command.options;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.command.Command;
|
||||
import net.dv8tion.jda.api.entities.channel.ChannelType;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData;
|
||||
import net.dv8tion.jda.internal.interactions.CommandDataImpl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class CommandOptions {
|
||||
private final Command command;
|
||||
private final CommandDataImpl commandData;
|
||||
private final List<OptionData> options;
|
||||
private final List<SubcommandData> subcommands;
|
||||
private final List<SubcommandGroupData> subcommandGroups;
|
||||
|
||||
public CommandOptions(Command command, CommandDataImpl commandData) {
|
||||
this.command = command;
|
||||
this.commandData = commandData;
|
||||
this.options = commandData.getOptions();
|
||||
this.subcommands = commandData.getSubcommands();
|
||||
this.subcommandGroups = commandData.getSubcommandGroups();
|
||||
}
|
||||
|
||||
public Command getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public SlashCommandData getSlashCommandData() {
|
||||
return commandData;
|
||||
}
|
||||
|
||||
public List<OptionData> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public List<SubcommandData> getSubcommands() {
|
||||
return subcommands;
|
||||
}
|
||||
|
||||
public List<SubcommandGroupData> getSubcommandGroups() {
|
||||
return subcommandGroups;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return options.isEmpty() && subcommands.isEmpty() && subcommandGroups.isEmpty();
|
||||
}
|
||||
|
||||
public String printUsage() {
|
||||
StringBuilder usage = new StringBuilder();
|
||||
if (!options.isEmpty()) {
|
||||
usage.append("- Usage: /").append(command.getCommandName());
|
||||
for (OptionData option : options) {
|
||||
usage.append(" <").append(option.getName()).append(">");
|
||||
}
|
||||
|
||||
usage.append(printOptions(options, null, false));
|
||||
}
|
||||
|
||||
if (!subcommands.isEmpty()) {
|
||||
for (SubcommandData subcommand : subcommands) {
|
||||
usage.append("- Usage: /").append(command.getCommandName()).append(" ").append(subcommand.getName());
|
||||
|
||||
for (OptionData option : subcommand.getOptions()) {
|
||||
usage.append(" <").append(option.getName()).append(">");
|
||||
}
|
||||
|
||||
usage.append(" (").append(subcommand.getDescription()).append(")");
|
||||
usage.append(printOptions(subcommand.getOptions(), null, false));
|
||||
|
||||
usage.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!subcommandGroups.isEmpty()) {
|
||||
for (SubcommandGroupData subcommandGroup : subcommandGroups) {
|
||||
usage.append("- Subcommand: /").append(command.getCommandName())
|
||||
.append(" ").append(subcommandGroup.getName())
|
||||
.append(" (").append(subcommandGroup.getDescription()).append(")")
|
||||
.append("\n");
|
||||
|
||||
for (SubcommandData subcommand : subcommandGroup.getSubcommands()) {
|
||||
usage.append(" - Usage: /").append(command.getCommandName())
|
||||
.append(" ").append(subcommandGroup.getName())
|
||||
.append(" ").append(subcommand.getName());
|
||||
|
||||
for (OptionData option : subcommand.getOptions()) {
|
||||
usage.append(" <").append(option.getName()).append(">");
|
||||
}
|
||||
|
||||
usage.append(printOptions(subcommand.getOptions(), subcommand.getDescription(), true));
|
||||
|
||||
usage.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEmpty()) {
|
||||
usage.append("\n\n-# *: required argument");
|
||||
}
|
||||
|
||||
return usage.toString();
|
||||
}
|
||||
|
||||
private String printOptions(List<OptionData> options, String description, boolean group) {
|
||||
StringBuilder usage = new StringBuilder();
|
||||
|
||||
if (description != null) {
|
||||
usage.append(" (").append(description).append(")");
|
||||
}
|
||||
|
||||
for (OptionData option : options) {
|
||||
usage.append("\n");
|
||||
if (group) usage.append(" ");
|
||||
usage.append(" - ");
|
||||
if (option.isRequired()) {
|
||||
usage.append("*");
|
||||
}
|
||||
usage.append(option.getName()).append(": ").append(option.getDescription());
|
||||
|
||||
if (option.getMinValue() != null) {
|
||||
usage.append(" [Min value: ").append(option.getMinValue().longValue()).append("]");
|
||||
}
|
||||
|
||||
if (option.getMaxValue() != null) {
|
||||
usage.append(" [Max value: ").append(option.getMaxValue().longValue()).append("]");
|
||||
}
|
||||
|
||||
if (option.getMinLength() != null) {
|
||||
usage.append(" [Min length: ").append(option.getMinLength().longValue()).append("]");
|
||||
}
|
||||
|
||||
if (option.getMaxLength() != null) {
|
||||
usage.append(" [Max length: ").append(option.getMaxLength().longValue()).append("]");
|
||||
}
|
||||
|
||||
List<net.dv8tion.jda.api.interactions.commands.Command.Choice> choices = option.getChoices();
|
||||
if (!choices.isEmpty()) {
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
for (net.dv8tion.jda.api.interactions.commands.Command.Choice choice : choices) {
|
||||
joiner.add(choice.getAsString());
|
||||
}
|
||||
|
||||
usage.append(" [Available choices: ").append(joiner).append("]");
|
||||
}
|
||||
|
||||
Set<ChannelType> requiredChannelTypes = option.getChannelTypes();
|
||||
if (!requiredChannelTypes.isEmpty()) {
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
for (ChannelType type : requiredChannelTypes) {
|
||||
joiner.add(type.name());
|
||||
}
|
||||
|
||||
usage.append(" [Required channel types: ").append(joiner).append("]");
|
||||
}
|
||||
}
|
||||
|
||||
return usage.toString();
|
||||
}
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package me.bobert.netneutrality.core.command.options;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.command.Command;
|
||||
import net.dv8tion.jda.api.interactions.DiscordLocale;
|
||||
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.*;
|
||||
import net.dv8tion.jda.api.interactions.commands.localization.LocalizationFunction;
|
||||
import net.dv8tion.jda.api.interactions.commands.localization.LocalizationMap;
|
||||
import net.dv8tion.jda.api.utils.data.DataObject;
|
||||
import net.dv8tion.jda.internal.interactions.CommandDataImpl;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class CommandOptionsBuilder implements SlashCommandData {
|
||||
private final Command command;
|
||||
private CommandDataImpl commandData;
|
||||
|
||||
public CommandOptionsBuilder(Command.Type type, Command command) {
|
||||
this.command = command;
|
||||
|
||||
if (type == Command.Type.SLASH) {
|
||||
commandData = (CommandDataImpl) Commands.slash(command.getCommandName(), command.getDescription());
|
||||
}
|
||||
|
||||
if (type == Command.Type.USER) {
|
||||
commandData = (CommandDataImpl) Commands.user(command.getCommandName());
|
||||
}
|
||||
|
||||
if (type == Command.Type.MESSAGE) {
|
||||
commandData = (CommandDataImpl) Commands.message(command.getCommandName());
|
||||
}
|
||||
}
|
||||
|
||||
public CommandOptions build() {
|
||||
return new CommandOptions(command, commandData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setLocalizationFunction(@Nonnull LocalizationFunction localizationFunction) {
|
||||
return commandData.setLocalizationFunction(localizationFunction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setName(@Nonnull String name) {
|
||||
return commandData.setName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setNameLocalization(@Nonnull DiscordLocale locale, @Nonnull String name) {
|
||||
return commandData.setNameLocalization(locale, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setNameLocalizations(@Nonnull Map<DiscordLocale, String> map) {
|
||||
return commandData.setNameLocalizations(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setDefaultPermissions(@Nonnull DefaultMemberPermissions permission) {
|
||||
return commandData.setDefaultPermissions(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setGuildOnly(boolean guildOnly) {
|
||||
return commandData.setGuildOnly(guildOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setNSFW(boolean nsfw) {
|
||||
return commandData.setNSFW(nsfw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull String getName() {
|
||||
return commandData.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull LocalizationMap getNameLocalizations() {
|
||||
return commandData.getNameLocalizations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull net.dv8tion.jda.api.interactions.commands.Command.Type getType() {
|
||||
return commandData.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull DefaultMemberPermissions getDefaultPermissions() {
|
||||
return commandData.getDefaultPermissions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGuildOnly() {
|
||||
return commandData.isGuildOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNSFW() {
|
||||
return commandData.isNSFW();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setDescription(@Nonnull String description) {
|
||||
return commandData.setDescription(description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setDescriptionLocalization(@Nonnull DiscordLocale locale, @Nonnull String description) {
|
||||
return commandData.setDescriptionLocalization(locale, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData setDescriptionLocalizations(@Nonnull Map<DiscordLocale, String> map) {
|
||||
return commandData.setDescriptionLocalizations(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull String getDescription() {
|
||||
return commandData.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull LocalizationMap getDescriptionLocalizations() {
|
||||
return commandData.getDescriptionLocalizations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeOptions(@Nonnull Predicate<? super OptionData> condition) {
|
||||
return commandData.removeOptions(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeSubcommands(@Nonnull Predicate<? super SubcommandData> condition) {
|
||||
return commandData.removeSubcommands(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeSubcommandGroups(@Nonnull Predicate<? super SubcommandGroupData> condition) {
|
||||
return commandData.removeSubcommandGroups(condition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull List<SubcommandData> getSubcommands() {
|
||||
return commandData.getSubcommands();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull List<SubcommandGroupData> getSubcommandGroups() {
|
||||
return commandData.getSubcommandGroups();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull List<OptionData> getOptions() {
|
||||
return commandData.getOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData addOptions(@Nonnull OptionData... options) {
|
||||
return commandData.addOptions(options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData addSubcommands(@Nonnull SubcommandData... subcommands) {
|
||||
return commandData.addSubcommands(subcommands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull SlashCommandData addSubcommandGroups(@Nonnull SubcommandGroupData... groups) {
|
||||
return commandData.addSubcommandGroups(groups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nonnull DataObject toData() {
|
||||
return commandData.toData();
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ package me.bobert.netneutrality.core.context;
|
||||
*/
|
||||
|
||||
import io.sentry.Sentry;
|
||||
import me.bobert.netneutrality.context.command.SlashCommandContext;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package me.bobert.netneutrality.core.tasks;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.context.TaskContext;
|
||||
|
||||
public abstract class AbstractBuiltInTask extends AbstractTask implements BuiltInTask {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replyToInteraction(CommandContext context) {
|
||||
// Task is loaded at runtime, this will never be called
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifecycle execute(TaskContext context) {
|
||||
executeTask(context);
|
||||
return Lifecycle.BUILTIN;
|
||||
}
|
||||
|
||||
public abstract void executeTask(TaskContext context);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package me.bobert.netneutrality.core.tasks;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public abstract class AbstractPersistableTask extends AbstractTask implements PersistableTask {
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replyToInteraction(CommandContext context) {
|
||||
// Task loaded from database, this will never be called
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(CommandContext context) {
|
||||
if (TaskManager.getInstance().hasTask(getId())) {
|
||||
throw new RuntimeException("Cannot insert a task that already exists");
|
||||
}
|
||||
|
||||
TaskManager.getInstance().insert(context, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
if (!TaskManager.getInstance().hasTask(getId())) {
|
||||
throw new RuntimeException("Cannot save a task that doesn't exist yet");
|
||||
}
|
||||
|
||||
TaskManager.getInstance().getTaskService().persistTask(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
TaskManager.getInstance().getTaskService().unpersistTask(this);
|
||||
TaskManager.getInstance().removeTask(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toPayload() {
|
||||
JSONObject payload = new JSONObject(this);
|
||||
|
||||
return payload.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package me.bobert.netneutrality.core.tasks;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class AbstractTask implements Task {
|
||||
private final OffsetDateTime creationTime;
|
||||
|
||||
public AbstractTask() {
|
||||
creationTime = OffsetDateTime.now();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffsetDateTime getCreationTime() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(CommandContext context) {
|
||||
TaskManager.getInstance().insert(context, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AbstractTask that = (AbstractTask) o;
|
||||
return Objects.equals(getId(), that.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Task{id=%s, lockId=%s, class=%s, name=%s, creationTime=%s}", getId(), getLockId(), getClass().getSimpleName(), getName(), getCreationTime());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package me.bobert.netneutrality.core.tasks;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import net.dv8tion.jda.api.interactions.components.buttons.Button;
|
||||
|
||||
public abstract class GenericCustomIdTask extends AbstractTask {
|
||||
private final String customId;
|
||||
|
||||
public GenericCustomIdTask(String id) {
|
||||
this.customId = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return customId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Button createButton() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package me.bobert.netneutrality.core.tasks;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class GenericRandomIdTask extends GenericCustomIdTask {
|
||||
public GenericRandomIdTask() {
|
||||
super(UUID.randomUUID().toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package me.bobert.netneutrality.core.tasks;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
public interface IStepTask {
|
||||
|
||||
/**
|
||||
* Defines the type of input expected for a step.
|
||||
*/
|
||||
enum StepType {
|
||||
/**
|
||||
* Expects a string input from the user.
|
||||
*/
|
||||
STRING,
|
||||
|
||||
/**
|
||||
* Expects a valid role ID for the current guild.
|
||||
* The role must exist in the guild where the command was executed.
|
||||
*/
|
||||
ROLE,
|
||||
|
||||
/**
|
||||
* Expects a valid emoji.
|
||||
*/
|
||||
EMOJI
|
||||
}
|
||||
|
||||
class StepResult {
|
||||
private enum ResultType {
|
||||
SUCCESS, FAILURE
|
||||
}
|
||||
|
||||
private final ResultType type;
|
||||
private final String message;
|
||||
private final Task nextStep;
|
||||
|
||||
/**
|
||||
* Represents the result of a step execution. Each step can either succeed, fail, or transition to another step.
|
||||
*/
|
||||
private StepResult(ResultType type, String message, Task nextStep) {
|
||||
this.type = type;
|
||||
this.message = message;
|
||||
this.nextStep = nextStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the step was completed successfully, with an optional follow-up step.
|
||||
*
|
||||
* @param message the success message
|
||||
* @param nextStep the next step in the workflow, or null if this is the final step
|
||||
* @return a successful result
|
||||
*/
|
||||
public static StepResult success(String message, Task nextStep) {
|
||||
return new StepResult(ResultType.SUCCESS, message, nextStep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the step was completed successfully.
|
||||
*
|
||||
* @param message the success message
|
||||
* @return a successful result without a next step
|
||||
*/
|
||||
public static StepResult success(String message) {
|
||||
return new StepResult(ResultType.SUCCESS, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the step has failed.
|
||||
*
|
||||
* @param message the failure message
|
||||
* @return a failed result
|
||||
*/
|
||||
public static StepResult failure(String message) {
|
||||
return new StepResult(ResultType.FAILURE, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves directly to the next step without displaying a message.
|
||||
*
|
||||
* @param nextTask the next task in the workflow
|
||||
* @return a successful result that advances to the next step
|
||||
*/
|
||||
public static StepResult next(Task nextTask) {
|
||||
return new StepResult(ResultType.SUCCESS, null, nextTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the message associated with the step result.
|
||||
*
|
||||
* @return the result message, or null if there is no message
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next step in the task workflow.
|
||||
*
|
||||
* @return the next step, or null if this is the last step
|
||||
*/
|
||||
public Task getNextStep() {
|
||||
return nextStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the step execution was successful.
|
||||
*
|
||||
* @return true if the step was successful, false otherwise
|
||||
*/
|
||||
public boolean isSuccess() {
|
||||
return type == ResultType.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of step input expected.
|
||||
*
|
||||
* @return the step type
|
||||
*/
|
||||
StepType getStepType();
|
||||
|
||||
/**
|
||||
* Provides a general description of the step. This will be displayed before asking the question.
|
||||
*
|
||||
* @return the step description
|
||||
*/
|
||||
String getStepDescription();
|
||||
|
||||
/**
|
||||
* Provides the specific question for this step.
|
||||
*
|
||||
* @return the step question
|
||||
*/
|
||||
String getStepQuestion();
|
||||
|
||||
/**
|
||||
* Executes the step using the provided answer.
|
||||
*
|
||||
* @param answer the user's input, validated against the expected step type
|
||||
* @return the result of executing this step
|
||||
*/
|
||||
StepResult executeStep(Object answer);
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package me.bobert.netneutrality.core.tasks.impl;
|
||||
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.core.context.CommandContext;
|
||||
import me.bobert.netneutrality.core.context.MessageContext;
|
||||
import me.bobert.netneutrality.core.context.TaskContext;
|
||||
import me.bobert.netneutrality.core.tasks.AbstractTask;
|
||||
import me.bobert.netneutrality.core.tasks.IStepTask;
|
||||
import me.bobert.netneutrality.core.tasks.TaskManager;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.interactions.components.buttons.Button;
|
||||
import net.fellbaum.jemoji.Emoji;
|
||||
import net.fellbaum.jemoji.EmojiManager;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Represents a task that consists of multiple sequential steps. The task starts with an initial message (question)
|
||||
* and expects a user response. Each step can lead to another step, forming a workflow.
|
||||
*/
|
||||
public abstract class StepTask extends AbstractTask implements IStepTask {
|
||||
private final Object stepLock = new Object();
|
||||
private CommandContext commandContext;
|
||||
private Guild guild;
|
||||
private String id = UUID.randomUUID().toString();
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInsertable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Guild getGuild() {
|
||||
return guild;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replyToInteraction(CommandContext context) {
|
||||
synchronized (stepLock) {
|
||||
this.commandContext = context;
|
||||
}
|
||||
|
||||
if (context.isFromGuild()) {
|
||||
guild = context.getGuild();
|
||||
}
|
||||
|
||||
if (guild == null && getStepType() == StepType.ROLE) {
|
||||
throw new IllegalArgumentException("Step task is of type role but it was inserted in a non-guild context");
|
||||
}
|
||||
|
||||
context.replyEphemeral("Please follow the instructions sent in DM.");
|
||||
context.sendMessageInPrivate(getStepDescription() + "\n\n" + getStepQuestion(),
|
||||
asyncContext -> assignId(asyncContext.getMessageId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lifecycle execute(TaskContext context) {
|
||||
synchronized (stepLock) {
|
||||
if (!context.getDiscordUser().equals(commandContext.getDiscordUser())) {
|
||||
return Lifecycle.KEEP;
|
||||
}
|
||||
}
|
||||
|
||||
if (context instanceof MessageContext messageContext) {
|
||||
Message message = messageContext.getMessage();
|
||||
String input = message.getContentRaw();
|
||||
|
||||
|
||||
Object answer = validateInput(context, input);
|
||||
if (answer == null) {
|
||||
return Lifecycle.KEEP;
|
||||
}
|
||||
|
||||
StepResult result = executeStep(answer);
|
||||
if (!result.isSuccess()) {
|
||||
context.replyEphemeral(result.getMessage());
|
||||
return Lifecycle.KEEP;
|
||||
}
|
||||
|
||||
if (result.getMessage() != null) {
|
||||
context.replyEphemeral(result.getMessage());
|
||||
}
|
||||
|
||||
if (result.getNextStep() != null) {
|
||||
result.getNextStep().insert(commandContext);
|
||||
}
|
||||
|
||||
return Lifecycle.REMOVE_SELF;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Step task is not of type MessageContext");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isExpired() {
|
||||
// is it really needed to expire this type of task?
|
||||
return getCreationTime().plusMinutes(60).isBefore(OffsetDateTime.now());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Button createButton() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the user input against the expected step type.
|
||||
*
|
||||
* @param context the task execution context
|
||||
* @param input the user-provided input
|
||||
* @return the parsed input if valid, or null if invalid
|
||||
*/
|
||||
private Object validateInput(TaskContext context, String input) {
|
||||
switch (getStepType()) {
|
||||
case ROLE -> {
|
||||
try {
|
||||
Role role = guild.getRoleById(input);
|
||||
if (role == null) {
|
||||
context.replyEphemeral("The role doesn't exist");
|
||||
return null;
|
||||
}
|
||||
|
||||
return role;
|
||||
} catch (NumberFormatException e) {
|
||||
context.replyEphemeral("Not a valid role ID");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
case EMOJI -> {
|
||||
Optional<Emoji> parsed = EmojiManager.getEmoji(input);
|
||||
|
||||
if (parsed.isPresent()) {
|
||||
return parsed.get().getEmoji();
|
||||
}
|
||||
|
||||
context.replyEphemeral("Not a valid emoji");
|
||||
return null;
|
||||
}
|
||||
case STRING -> {
|
||||
return input;
|
||||
}
|
||||
default -> throw new IllegalStateException("Unknown step type: " + getStepType());
|
||||
}
|
||||
}
|
||||
|
||||
private void assignId(String newId) {
|
||||
if (newId == null || newId.isBlank()) {
|
||||
throw new IllegalArgumentException("Task ID cannot be null or empty.");
|
||||
}
|
||||
|
||||
String oldId = id;
|
||||
synchronized (this) {
|
||||
this.id = newId;
|
||||
TaskManager.getInstance().activateTask(this, oldId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import me.bobert.netneutrality.utils.MessageFunction;
|
||||
import me.bobert.netneutrality.utils.MusicUtils;
|
||||
import net.dv8tion.jda.api.components.buttons.ButtonStyle;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
|
||||
|
||||
public class LoadTrackFromPlaylistTask extends AcceptButton<LoadPlaylistTask> {
|
||||
private final AudioTrack track;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package me.bobert.netneutrality.thread;
|
||||
/*
|
||||
* Copyright (c) anthorob
|
||||
*
|
||||
* https://discord.gg/qUa6zNFZsd
|
||||
*/
|
||||
|
||||
import me.bobert.netneutrality.music.MusicManager;
|
||||
import me.bobert.netneutrality.music.TrackScheduler;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class MusicManagerCleanupThread implements Runnable {
|
||||
private static final Logger logger = LogManager.getLogger(MusicManagerCleanupThread.class);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
|
||||
for (MusicManager manager : MusicManager.getManagers()) {
|
||||
processManager(manager);
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Interrupted while running MusicManagerCleanupThread", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processManager(MusicManager manager) throws InterruptedException {
|
||||
TrackScheduler scheduler = manager.getScheduler();
|
||||
|
||||
// Context is still attached after bot is disconnected, the bot might have been kicked from the channel
|
||||
if (scheduler.getContext() != null && !manager.isConnected()) {
|
||||
manager.disconnect();
|
||||
manager.getQueueManager().clearQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user