develop #4

Merged
sebclem merged 6 commits from develop into main 2023-12-29 16:32:23 +01:00
83 changed files with 1473 additions and 1654 deletions
Showing only changes of commit b03bfeb28c - Show all commits

59
.dockerignore Normal file
View File

@ -0,0 +1,59 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
.gradle
**/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
# Cache of project
.gradletasknamecache
# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix

View File

@ -16,10 +16,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
@ -41,10 +41,10 @@ jobs:
needs: needs:
- build-gradle - build-gradle
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Download artifact - name: Download artifact
uses: actions/download-artifact@v3.0.0 uses: actions/download-artifact@v3.0.2
with: with:
# Artifact name # Artifact name
name: claptrap_jar name: claptrap_jar
@ -52,10 +52,10 @@ jobs:
path: build/libs/ path: build/libs/
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io - name: Login to ghcr.io
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
@ -70,7 +70,7 @@ jobs:
echo "tag=${{ steps.branch-name.outputs.current_branch }}" >> $GITHUB_ENV echo "tag=${{ steps.branch-name.outputs.current_branch }}" >> $GITHUB_ENV
- name: Build and push Docker - name: Build and push Docker
uses: docker/build-push-action@v3 uses: docker/build-push-action@v5
with: with:
push: true push: true
context: . context: .

View File

@ -14,10 +14,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 17 java-version: 17
@ -39,10 +39,10 @@ jobs:
needs: needs:
- build-gradle - build-gradle
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Download artifact - name: Download artifact
uses: actions/download-artifact@v3.0.0 uses: actions/download-artifact@v3.0.2
with: with:
# Artifact name # Artifact name
name: claptrap_jar name: claptrap_jar
@ -50,10 +50,10 @@ jobs:
path: build/libs/ path: build/libs/
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Login to ghcr.io - name: Login to ghcr.io
uses: docker/login-action@v2 uses: docker/login-action@v3
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
@ -68,7 +68,7 @@ jobs:
echo "tag=${{ steps.branch-name.outputs.tag }}" >> $GITHUB_ENV echo "tag=${{ steps.branch-name.outputs.tag }}" >> $GITHUB_ENV
- name: Build and push Docker - name: Build and push Docker
uses: docker/build-push-action@v3 uses: docker/build-push-action@v5
with: with:
push: true push: true
context: . context: .

69
.gitignore vendored
View File

@ -1,36 +1,59 @@
.idea/ # Compiled class file
.gradle
config/
lib/
logs/
out/
/build/
*.iml
META-INF/
*.uml
*.class *.class
# Log file
*.log
classes/artifacts/Discord_Stroumpf_Beta_jar/ # BlueJ files
*.ctxt
src/main/resources/templates/css # Mobile Tools for Java (J2ME)
.mtj.tmp/
src/main/resources/templates/js # Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
\.directory # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
\.credentials/ .gradle
**/build/
!src/**/build/
src/main/resources/static/error/css # Ignore Gradle GUI config
gradle-app.setting
src/main/resources/static/error/js # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
**.log # Cache of project
.jpb/ .gradletasknamecache
**/*.env # Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
bin/ .vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix

View File

@ -1,3 +1,7 @@
{ {
"java.configuration.updateBuildConfiguration": "automatic" "java.configuration.updateBuildConfiguration": "automatic",
"java.compile.nullAnalysis.mode": "disabled",
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
} }

View File

@ -0,0 +1,33 @@
steps:
build-dev:
image: woodpeckerci/plugin-docker-buildx
settings:
repo: git.sebclem.fr/sebclem/${CI_REPO_NAME,,}
cache_from: git.sebclem.fr/sebclem/${CI_REPO_NAME,,}
registry: git.sebclem.fr
auto_tag: true
logins:
- registry: https://git.sebclem.fr
username:
from_secret: docker_user
password:
from_secret: docker_token
when:
event: [push, pull_request, manual]
publish:
image: woodpeckerci/plugin-docker-buildx
settings:
platforms: linux/amd64
auto_tag: true
repo: git.sebclem.fr/sebclem/${CI_REPO_NAME,,}
cache_from: git.sebclem.fr/sebclem/${CI_REPO_NAME,,}
logins:
- registry: https://git.sebclem.fr
username:
from_secret: docker_user
password:
from_secret: docker_token
when:
event:
- tag

View File

@ -1,10 +1,15 @@
FROM openjdk:18.0.1 FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /bot_src WORKDIR /workspace/app
ARG BUILD_NBR COPY . /workspace/app
ARG BRANCH_NAME
ARG BRANCH_NAME RUN ./gradlew clean build
ARG GITHUB_RUN_NUMBER RUN mkdir -p build/dependency && (cd build/dependency; jar -xf ../libs/*.jar)
ADD build/libs/ClaptrapBot.jar /bot_src/claptrapbot.jar
RUN java -version
CMD java -jar claptrapbot.jar FROM eclipse-temurin:21-jdk-alpine
LABEL org.opencontainers.image.source=https://github.com/Sebclem/ClaptrapBot/ ARG DEPENDENCY=/workspace/app/build/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","net.Broken.MainBot"]
LABEL org.opencontainers.image.source=https://git.sebclem.fr/sebclem/ClaptrapBot

View File

@ -1,16 +1,16 @@
plugins { plugins {
id 'org.springframework.boot' version '2.7.2' id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.0.12.RELEASE' id 'io.spring.dependency-management' version '1.1.4'
id 'java' id 'java'
id 'groovy' id 'groovy'
id 'org.liquibase.gradle' version '2.1.1' id 'org.liquibase.gradle' version '2.2.1'
id "nebula.lint" version "17.7.0" id "nebula.lint" version "19.0.1"
id "com.gorylenko.gradle-git-properties" version "2.4.1" id "com.gorylenko.gradle-git-properties" version "2.4.1"
} }
group = "net.broken" group = "net.broken"
archivesBaseName = "ClaptrapBot" archivesBaseName = "ClaptrapBot"
sourceCompatibility = '17' sourceCompatibility = JavaVersion.VERSION_21.toString()
repositories { repositories {
mavenCentral() mavenCentral()
@ -33,38 +33,38 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter-log4j2") implementation("org.springframework.boot:spring-boot-starter-log4j2")
implementation("org.springframework.boot:spring-boot-starter-oauth2-client") implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
implementation('org.springframework.boot:spring-boot-starter-actuator') implementation('org.springframework.boot:spring-boot-starter-actuator')
implementation('io.micrometer:micrometer-registry-prometheus:1.9.2') implementation('io.micrometer:micrometer-registry-prometheus:1.12.1')
implementation('org.springdoc:springdoc-openapi-ui:1.6.9') implementation('org.springdoc:springdoc-openapi-ui:1.7.0')
implementation('org.springdoc:springdoc-openapi-security:1.6.9') implementation('org.springdoc:springdoc-openapi-security:1.7.0')
implementation('org.liquibase:liquibase-core') implementation('org.liquibase:liquibase-core')
implementation('io.jsonwebtoken:jjwt-api:0.11.5') implementation('io.jsonwebtoken:jjwt-api:0.12.3')
implementation('io.jsonwebtoken:jjwt-impl:0.11.5') implementation('io.jsonwebtoken:jjwt-impl:0.12.3')
implementation('io.jsonwebtoken:jjwt-jackson:0.11.5') implementation('io.jsonwebtoken:jjwt-jackson:0.12.3')
implementation('com.sedmelluq:lavaplayer:1.3.78') implementation('com.sedmelluq:lavaplayer:1.3.78')
implementation('net.dv8tion:JDA:4.4.1_353') implementation('net.dv8tion:JDA:5.0.0-beta.18')
implementation(platform("org.apache.logging.log4j:log4j-bom:2.18.0")) implementation(platform("org.apache.logging.log4j:log4j-bom:2.22.1"))
implementation group: 'org.hibernate', name: 'hibernate-validator', version: '7.0.4.Final' implementation group: 'org.hibernate', name: 'hibernate-validator', version: '8.0.1.Final'
// Use MySQL Connector-J // Use MySQL Connector-J
implementation('mysql:mysql-connector-java:8.0.30') implementation('mysql:mysql-connector-java:8.0.33')
implementation('org.reflections:reflections:0.10.2') implementation('org.reflections:reflections:0.10.2')
implementation('org.apache.commons:commons-lang3:3.12.0') implementation('org.apache.commons:commons-lang3:3.14.0')
liquibaseRuntime('org.liquibase:liquibase-core:4.14.0') liquibaseRuntime('org.liquibase:liquibase-core:4.25.1')
liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:3.0.2') liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:3.0.3')
liquibaseRuntime('mysql:mysql-connector-java:8.0.30') liquibaseRuntime('mysql:mysql-connector-java:8.0.33')
liquibaseRuntime group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1' liquibaseRuntime group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
liquibaseRuntime group: 'org.liquibase.ext', name: 'liquibase-hibernate5', version: '4.14.0' liquibaseRuntime group: 'org.liquibase.ext', name: 'liquibase-hibernate5', version: '4.25.1'
liquibaseRuntime 'org.springframework.boot:spring-boot-starter-data-jpa' liquibaseRuntime 'org.springframework.boot:spring-boot-starter-data-jpa'
liquibaseRuntime 'org.springframework.data:spring-data-jpa' liquibaseRuntime 'org.springframework.data:spring-data-jpa'
liquibaseRuntime 'org.springframework:spring-beans' liquibaseRuntime 'org.springframework:spring-beans'
liquibaseRuntime 'net.dv8tion:JDA:4.4.0_352' liquibaseRuntime 'net.dv8tion:JDA:5.0.0-beta.18'
liquibaseRuntime 'com.sedmelluq:lavaplayer:1.3.78' liquibaseRuntime 'com.sedmelluq:lavaplayer:1.3.78'
liquibaseRuntime sourceSets.main.output liquibaseRuntime sourceSets.main.output

Binary file not shown.

View File

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

294
gradlew vendored Normal file → Executable file
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh #!/bin/sh
# #
# Copyright 2015 the original author or authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -17,67 +17,99 @@
# #
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" # This is normally unused
APP_BASE_NAME=`basename "$0"` # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -87,9 +119,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -98,88 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
MAX_FD="$MAX_FD_LIMIT" # shellcheck disable=SC2039,SC3045
fi MAX_FD=$( ulimit -H -n ) ||
ulimit -n $MAX_FD warn "Could not query maximum file descriptor limit"
if [ $? -ne 0 ] ; then esac
warn "Could not set maximum file descriptor limit: $MAX_FD" case $MAX_FD in #(
fi '' | soft) :;; #(
else *)
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
fi # shellcheck disable=SC2039,SC3045
fi ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

15
gradlew.bat vendored
View File

@ -14,7 +14,7 @@
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

View File

@ -23,60 +23,60 @@ public class AudioController {
this.audioService = audioService; this.audioService = audioService;
} }
@GetMapping("/{guildId}/status") @GetMapping("/{guildId}/status")
@PreAuthorize("isInGuild(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId)")
public Status getMusicStatus(@PathVariable String guildId, Authentication authentication) { public Status getMusicStatus(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.getGuildAudioStatus(guildId, principal.user().getDiscordId()); return audioService.getGuildAudioStatus(guildId, principal.user().getDiscordId());
} }
@PostMapping("/{guildId}/connect") @PostMapping("/{guildId}/connect")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId, #body)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId, #body)")
public ResponseEntity<Status> connect(@PathVariable String guildId, @RequestBody Connect body, Authentication authentication) { public ResponseEntity<Status> connect(@PathVariable String guildId, @RequestBody Connect body,
Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.connect(guildId, body, principal.user().getDiscordId()); return audioService.connect(guildId, body, principal.user().getDiscordId());
} }
@PostMapping("/{guildId}/disconnect") @PostMapping("/{guildId}/disconnect")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> disconnect(@PathVariable String guildId, Authentication authentication) { public ResponseEntity<Status> disconnect(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.disconnect(guildId, principal.user().getDiscordId()); return audioService.disconnect(guildId, principal.user().getDiscordId());
} }
@PostMapping("/{guildId}/resume") @PostMapping("/{guildId}/resume")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> resume(@PathVariable String guildId, Authentication authentication) { public ResponseEntity<Status> resume(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.resume(guildId, principal.user().getDiscordId()); return audioService.resume(guildId, principal.user().getDiscordId());
} }
@PostMapping("/{guildId}/pause") @PostMapping("/{guildId}/pause")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> pause(@PathVariable String guildId, Authentication authentication) { public ResponseEntity<Status> pause(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.pause(guildId, principal.user().getDiscordId()); return audioService.pause(guildId, principal.user().getDiscordId());
} }
@PostMapping("/{guildId}/skip") @PostMapping("/{guildId}/skip")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> skip(@PathVariable String guildId, Authentication authentication) { public ResponseEntity<Status> skip(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.skip(guildId, principal.user().getDiscordId()); return audioService.skip(guildId, principal.user().getDiscordId());
} }
@PostMapping("/{guildId}/stop") @PostMapping("/{guildId}/stop")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> stop(@PathVariable String guildId, Authentication authentication) { public ResponseEntity<Status> stop(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.stop(guildId, principal.user().getDiscordId()); return audioService.stop(guildId, principal.user().getDiscordId());
} }
@PostMapping("/{guildId}/add") @PostMapping("/{guildId}/add")
@PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> add(@PathVariable String guildId, @RequestBody Add body, Authentication authentication) throws ExecutionException, InterruptedException { public ResponseEntity<Status> add(@PathVariable String guildId, @RequestBody Add body,
Authentication authentication) throws ExecutionException, InterruptedException {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return audioService.add(guildId, principal.user().getDiscordId(), body); return audioService.add(guildId, principal.user().getDiscordId(), body);
} }

View File

@ -19,7 +19,8 @@ public class AuthController {
private final JwtService jwtService; private final JwtService jwtService;
public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository, JwtService jwtService) { public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository,
JwtService jwtService) {
this.authenticationManager = authenticationManager; this.authenticationManager = authenticationManager;
this.jwtService = jwtService; this.jwtService = jwtService;
} }
@ -27,14 +28,12 @@ public class AuthController {
@PostMapping("/discord") @PostMapping("/discord")
public JwtResponse loginDiscord(@Validated @RequestBody Login login) { public JwtResponse loginDiscord(@Validated @RequestBody Login login) {
Authentication authentication = authenticationManager.authenticate( Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(login.redirectUri(), login.code()) new UsernamePasswordAuthenticationToken(login.redirectUri(), login.code()));
);
UserEntity user = (UserEntity) authentication.getPrincipal(); UserEntity user = (UserEntity) authentication.getPrincipal();
String jwt = jwtService.buildJwt(user); String jwt = jwtService.buildJwt(user);
return new JwtResponse(jwt); return new JwtResponse(jwt);
} }
} }

View File

@ -8,7 +8,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@RestController @RestController
@RequestMapping("/api/v2") @RequestMapping("/api/v2")
@CrossOrigin(origins = "*", maxAge = 3600) @CrossOrigin(origins = "*", maxAge = 3600)
@ -16,13 +15,10 @@ import org.springframework.web.bind.annotation.RestController;
public class CrossOptionController { public class CrossOptionController {
/** /**
* For cross preflight request send by axios * For cross preflight request send by axios
*/ */
@RequestMapping( @RequestMapping(value = "/**", method = RequestMethod.OPTIONS)
value = "/**",
method = RequestMethod.OPTIONS
)
public ResponseEntity<String> handle() { public ResponseEntity<String> handle() {
return new ResponseEntity<>("",HttpStatus.OK); return new ResponseEntity<>("", HttpStatus.OK);
} }
} }

View File

@ -41,21 +41,21 @@ public class GuildController {
} }
@GetMapping("/{guildId}/voiceChannels") @GetMapping("/{guildId}/voiceChannels")
@PreAuthorize("isInGuild(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId)")
public List<Channel> getVoiceChannels(@PathVariable String guildId, Authentication authentication) { public List<Channel> getVoiceChannels(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return guildService.getVoiceChannel(guildId, principal.user().getDiscordId()); return guildService.getVoiceChannel(guildId, principal.user().getDiscordId());
} }
@GetMapping("/{guildId}/textChannels") @GetMapping("/{guildId}/textChannels")
@PreAuthorize("isInGuild(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId)")
public List<Channel> getTextChannels(@PathVariable String guildId, Authentication authentication) { public List<Channel> getTextChannels(@PathVariable String guildId, Authentication authentication) {
JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal(); JwtPrincipal principal = (JwtPrincipal) authentication.getPrincipal();
return guildService.getTextChannel(guildId, principal.user().getDiscordId()); return guildService.getTextChannel(guildId, principal.user().getDiscordId());
} }
@GetMapping("/{guildId}/roles") @GetMapping("/{guildId}/roles")
@PreAuthorize("isInGuild(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId)")
public List<Role> getRoles(@PathVariable String guildId) { public List<Role> getRoles(@PathVariable String guildId) {
return guildService.getRole(guildId); return guildService.getRole(guildId);
} }

View File

@ -1,14 +1,21 @@
package net.Broken.Api.Controllers; package net.Broken.Api.Controllers;
import java.util.List;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import net.Broken.Api.Data.Settings.SettingGroup; import net.Broken.Api.Data.Settings.SettingGroup;
import net.Broken.Api.Data.Settings.Value; import net.Broken.Api.Data.Settings.Value;
import net.Broken.Api.Services.SettingService; import net.Broken.Api.Services.SettingService;
import net.Broken.DB.Entity.GuildPreferenceEntity; import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.Tools.Settings.SettingValueBuilder; import net.Broken.Tools.Settings.SettingValueBuilder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController @RestController
@RequestMapping("/api/v2/setting") @RequestMapping("/api/v2/setting")
@ -21,19 +28,19 @@ public class SettingController {
} }
@GetMapping("description") @GetMapping("description")
public List<SettingGroup> getSettingDescription(){ public List<SettingGroup> getSettingDescription() {
return settingService.getSettingDescription(); return settingService.getSettingDescription();
} }
@GetMapping("/{guildId}/values") @GetMapping("/{guildId}/values")
@PreAuthorize("isInGuild(#guildId) && canManageGuild(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canManageGuild(#guildId)")
public List<Value> getSettingValues(@PathVariable String guildId){ public List<Value> getSettingValues(@PathVariable String guildId) {
return settingService.getValues(guildId); return settingService.getValues(guildId);
} }
@PostMapping("/{guildId}/values") @PostMapping("/{guildId}/values")
@PreAuthorize("isInGuild(#guildId) && canManageGuild(#guildId)") @PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canManageGuild(#guildId)")
public List<Value> getSettingValues(@PathVariable String guildId, @RequestBody List<Value> values){ public List<Value> getSettingValues(@PathVariable String guildId, @RequestBody List<Value> values) {
GuildPreferenceEntity pref = settingService.saveValue(guildId, values); GuildPreferenceEntity pref = settingService.saveValue(guildId, values);
return new SettingValueBuilder(pref).build(); return new SettingValueBuilder(pref).build();
} }

View File

@ -1,6 +1,6 @@
package net.Broken.Api.Data; package net.Broken.Api.Data;
import javax.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
public record Login( public record Login(
@NotBlank String code, @NotBlank String redirectUri) { @NotBlank String code, @NotBlank String redirectUri) {

View File

@ -4,9 +4,8 @@ import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public record PlayBackInfo( public record PlayBackInfo(
Boolean paused, Boolean paused,
Boolean stopped, Boolean stopped,
Long progress, Long progress,
TrackInfo trackInfo TrackInfo trackInfo) {
) {
} }

View File

@ -6,11 +6,10 @@ import net.dv8tion.jda.api.audio.hooks.ConnectionStatus;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public record Status( public record Status(
Boolean connected, Boolean connected,
ConnectionStatus connectionStatus, ConnectionStatus connectionStatus,
Channel channel, Channel channel,
Boolean canView, Boolean canView,
Boolean canInteract, Boolean canInteract,
PlayBackInfo playBackInfo PlayBackInfo playBackInfo) {
) {
} }

View File

@ -7,7 +7,8 @@ import net.Broken.Audio.UserAudioTrack;
public record TrackInfo(UserInfo submitter, AudioTrackInfo detail) { public record TrackInfo(UserInfo submitter, AudioTrackInfo detail) {
public TrackInfo(UserAudioTrack userAudioTrack) { public TrackInfo(UserAudioTrack userAudioTrack) {
this(new UserInfo(userAudioTrack.getSubmittedUser().getId(), userAudioTrack.getSubmittedUser().getName(), userAudioTrack.getSubmittedUser().getAvatarUrl()), this(new UserInfo(userAudioTrack.getSubmittedUser().getId(), userAudioTrack.getSubmittedUser().getName(),
userAudioTrack.getSubmittedUser().getAvatarUrl()),
userAudioTrack.getAudioTrack().getInfo()); userAudioTrack.getAudioTrack().getInfo());
} }
} }

View File

@ -7,8 +7,7 @@ public record SettingDescriber(
String id, String id,
String name, String name,
String description, String description,
TYPE type TYPE type) {
) {
public enum TYPE { public enum TYPE {
BOOL, LIST, STRING, ROLE, TEXT_CHANNEL, VOICE_CHANNEL BOOL, LIST, STRING, ROLE, TEXT_CHANNEL, VOICE_CHANNEL

View File

@ -6,8 +6,7 @@ import java.util.List;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public record SettingGroup( public record SettingGroup(
String name, String name,
SettingDescriber mainField, SettingDescriber mainField,
List<SettingDescriber> fields List<SettingDescriber> fields) {
) {
} }

View File

@ -28,8 +28,8 @@ public class OpenApiConfig {
new SecurityScheme().name(securitySchemeName) new SecurityScheme().name(securitySchemeName)
.type(SecurityScheme.Type.HTTP) .type(SecurityScheme.Type.HTTP)
.scheme("bearer") .scheme("bearer")
.bearerFormat("JWT")) .bearerFormat("JWT")))
).addServersItem(new Server().url("/").description("Default")) .addServersItem(new Server().url("/").description("Default"))
.info(new Info().title("ClaptrapBot API").version(versionLoader.getVersion())); .info(new Info().title("ClaptrapBot API").version(versionLoader.getVersion()));
} }
} }

View File

@ -29,10 +29,12 @@ public class DiscordAuthenticationProvider implements AuthenticationProvider {
String token = discordOauthService.getAccessToken(code, redirectUri); String token = discordOauthService.getAccessToken(code, redirectUri);
DiscordOauthUserInfo discordOauthUserInfo = discordOauthService.getUserInfo(token); DiscordOauthUserInfo discordOauthUserInfo = discordOauthService.getUserInfo(token);
discordOauthService.revokeToken(token); discordOauthService.revokeToken(token);
DiscordOauthService.LoginOrRegisterResponse<UserEntity> loginOrRegisterResponse = discordOauthService.loginOrRegisterDiscordUser(discordOauthUserInfo); DiscordOauthService.LoginOrRegisterResponse<UserEntity> loginOrRegisterResponse = discordOauthService
.loginOrRegisterDiscordUser(discordOauthUserInfo);
UserEntity userEntity = loginOrRegisterResponse.response(); UserEntity userEntity = loginOrRegisterResponse.response();
if(!loginOrRegisterResponse.created()){ if (!loginOrRegisterResponse.created()) {
userEntity = discordOauthService.updateUserInfo(discordOauthUserInfo, loginOrRegisterResponse.response()); userEntity = discordOauthService.updateUserInfo(discordOauthUserInfo,
loginOrRegisterResponse.response());
} }
return new UsernamePasswordAuthenticationToken(userEntity, null, new ArrayList<>()); return new UsernamePasswordAuthenticationToken(userEntity, null, new ArrayList<>());
} catch (OAuthLoginFail e) { } catch (OAuthLoginFail e) {

View File

@ -1,15 +1,17 @@
package net.Broken.Api.Security.Components; package net.Broken.Api.Security.Components;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -19,7 +21,9 @@ public class UnauthorizedHandler implements AuthenticationEntryPoint {
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
@Override @Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { public void commence(HttpServletRequest request,
HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
logger.error("[API] Unauthorized error: {}", authException.getMessage()); logger.error("[API] Unauthorized error: {}", authException.getMessage());
response.setContentType(MediaType.APPLICATION_JSON_VALUE); response.setContentType(MediaType.APPLICATION_JSON_VALUE);

View File

@ -4,9 +4,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public record DiscordOauthUserInfo( public record DiscordOauthUserInfo(
String id, String id,
String username, String username,
String discriminator, String discriminator,
String avatar) { String avatar) {
} }

View File

@ -1,25 +0,0 @@
package net.Broken.Api.Security.Expression;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
public class CustomMethodSecurityExpressionHandler
extends DefaultMethodSecurityExpressionHandler {
private final AuthenticationTrustResolver trustResolver =
new AuthenticationTrustResolverImpl();
@Override
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(
Authentication authentication, MethodInvocation invocation) {
CustomMethodSecurityExpressionRoot root =
new CustomMethodSecurityExpressionRoot(authentication);
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(this.trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
return root;
}
}

View File

@ -1,102 +0,0 @@
package net.Broken.Api.Security.Expression;
import net.Broken.Api.Data.Music.Connect;
import net.Broken.Api.Security.Data.JwtPrincipal;
import net.Broken.Audio.GuildAudioBotService;
import net.Broken.MainBot;
import net.Broken.Tools.CacheTools;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.VoiceChannel;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.access.expression.method.MethodSecurityExpressionOperations;
import org.springframework.security.core.Authentication;
public class CustomMethodSecurityExpressionRoot
extends SecurityExpressionRoot
implements MethodSecurityExpressionOperations {
private Object filterObject;
private Object returnObject;
/**
* Creates a new instance
*
* @param authentication the {@link Authentication} to use. Cannot be null.
*/
public CustomMethodSecurityExpressionRoot(Authentication authentication) {
super(authentication);
}
public boolean isInGuild(String guildId){
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
return CacheTools.getJdaUser(jwtPrincipal.user()).getMutualGuilds().contains(guild);
}
public boolean canManageGuild(String guildId){
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
Member member = MainBot.jda.getGuildById(guildId).getMemberById(jwtPrincipal.user().getDiscordId());
return member.hasPermission(
Permission.MANAGE_SERVER,
Permission.MANAGE_PERMISSIONS,
Permission.MANAGE_CHANNEL
);
}
public boolean canInteractWithVoiceChannel(String guildId, Connect connectPayload){
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(jwtPrincipal.user().getDiscordId());
VoiceChannel channel = guild.getVoiceChannelById(connectPayload.channelId());
if( channel == null){
return false;
}
return (member.hasPermission(channel, Permission.VOICE_CONNECT)
|| member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel)
&& member.hasPermission(channel, Permission.VOICE_SPEAK);
}
public boolean canInteractWithVoiceChannel(String guildId) {
JwtPrincipal jwtPrincipal = (JwtPrincipal) authentication.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(guild);
VoiceChannel channel = guild.getAudioManager().getConnectedChannel();
if (channel == null) {
return false;
}
Member member = guild.getMemberById(jwtPrincipal.user().getDiscordId());
return (member.hasPermission(channel, Permission.VOICE_CONNECT)
|| member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel)
&& member.hasPermission(channel, Permission.VOICE_SPEAK);
}
@Override
public void setFilterObject(Object filterObject) {
this.filterObject = filterObject;
}
@Override
public Object getFilterObject() {
return this.filterObject;
}
@Override
public void setReturnObject(Object returnObject) {
this.returnObject = returnObject;
}
@Override
public Object getReturnObject() {
return this.returnObject;
}
@Override
public Object getThis() {
return this;
}
}

View File

@ -0,0 +1,69 @@
package net.Broken.Api.Security.Expression;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import net.Broken.MainBot;
import net.Broken.Api.Data.Music.Connect;
import net.Broken.Api.Security.Data.JwtPrincipal;
import net.Broken.Tools.CacheTools;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion;
@Service
public class WebSecurity {
public boolean isInGuild(String guildId) {
JwtPrincipal jwtPrincipal = (JwtPrincipal) SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
return CacheTools.getJdaUser(jwtPrincipal.user()).getMutualGuilds().contains(guild);
}
public boolean canManageGuild(String guildId) {
JwtPrincipal jwtPrincipal = (JwtPrincipal) SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
Member member = MainBot.jda.getGuildById(guildId).getMemberById(jwtPrincipal.user().getDiscordId());
return member.hasPermission(
Permission.MANAGE_SERVER,
Permission.MANAGE_PERMISSIONS,
Permission.MANAGE_CHANNEL);
}
public boolean canInteractWithVoiceChannel(String guildId, Connect connectPayload) {
JwtPrincipal jwtPrincipal = (JwtPrincipal) SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(jwtPrincipal.user().getDiscordId());
VoiceChannel channel = guild.getVoiceChannelById(connectPayload.channelId());
if (channel == null) {
return false;
}
return (member.hasPermission(channel, Permission.VOICE_CONNECT)
|| member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel)
&& member.hasPermission(channel, Permission.VOICE_SPEAK);
}
public boolean canInteractWithVoiceChannel(String guildId) {
JwtPrincipal jwtPrincipal = (JwtPrincipal) SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
Guild guild = MainBot.jda.getGuildById(guildId);
AudioChannelUnion channel = guild.getAudioManager().getConnectedChannel();
if (channel == null) {
return false;
}
Member member = guild.getMemberById(jwtPrincipal.user().getDiscordId());
return (member.hasPermission(channel, Permission.VOICE_CONNECT)
|| member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel)
&& member.hasPermission(channel, Permission.VOICE_SPEAK);
}
}

View File

@ -2,6 +2,10 @@ package net.Broken.Api.Security.Filters;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jws;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.Broken.Api.Security.Data.JwtPrincipal; import net.Broken.Api.Security.Data.JwtPrincipal;
import net.Broken.Api.Security.Services.JwtService; import net.Broken.Api.Security.Services.JwtService;
import net.Broken.BotConfigLoader; import net.Broken.BotConfigLoader;
@ -15,10 +19,6 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -32,23 +32,24 @@ public class JwtFilter extends OncePerRequestFilter {
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
@Override @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String authHeader = request.getHeader("Authorization"); String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) { if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.replace("Bearer ", ""); String token = authHeader.replace("Bearer ", "");
try { try {
UserEntity user; UserEntity user;
JwtPrincipal principal; JwtPrincipal principal;
if(config.mode().equals("DEV")){ if (config.mode().equals("DEV")) {
user = userRepository.findByDiscordId(token).orElseThrow(); user = userRepository.findByDiscordId(token).orElseThrow();
principal = new JwtPrincipal("DEV", user); principal = new JwtPrincipal("DEV", user);
} } else {
else {
Jws<Claims> jwt = jwtService.verifyAndParseJwt(token); Jws<Claims> jwt = jwtService.verifyAndParseJwt(token);
user = jwtService.getUserWithJwt(jwt); user = jwtService.getUserWithJwt(jwt);
principal = new JwtPrincipal(jwt.getBody().getId(), user); principal = new JwtPrincipal(jwt.getPayload().getId(), user);
} }
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(principal, null, new ArrayList<>()); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
principal, null, new ArrayList<>());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken); SecurityContextHolder.getContext().setAuthentication(authenticationToken);
} catch (Exception e) { } catch (Exception e) {

View File

@ -1,16 +0,0 @@
package net.Broken.Api.Security;
import net.Broken.Api.Security.Expression.CustomMethodSecurityExpressionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new CustomMethodSecurityExpressionHandler();
}
}

View File

@ -1,51 +1,57 @@
package net.Broken.Api.Security; package net.Broken.Api.Security;
import net.Broken.Api.Security.Components.UnauthorizedHandler; import static org.springframework.security.config.Customizer.withDefaults;
import net.Broken.Api.Security.Filters.JwtFilter;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import net.Broken.Api.Security.Components.UnauthorizedHandler;
import net.Broken.Api.Security.Filters.JwtFilter;
@EnableWebSecurity @EnableWebSecurity
@EnableMethodSecurity
@Configuration @Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig {
private final UnauthorizedHandler unauthorizedHandler; private final UnauthorizedHandler unauthorizedHandler;
public SecurityConfig(UnauthorizedHandler unauthorizedHandler) { public SecurityConfig(UnauthorizedHandler unauthorizedHandler) {
this.unauthorizedHandler = unauthorizedHandler; this.unauthorizedHandler = unauthorizedHandler;
} }
@Override @Bean
protected void configure(HttpSecurity http) throws Exception { public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable() http.cors(withDefaults()).csrf(csrf -> csrf.disable())
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() .exceptionHandling(handling -> handling.authenticationEntryPoint(unauthorizedHandler))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeRequests() .authorizeHttpRequests(requests -> requests
.antMatchers("/api/v2/auth/**").permitAll() .requestMatchers("/api/v2/auth/**").permitAll()
.antMatchers("/api/v2/guild/inviteLink").permitAll() .requestMatchers("/api/v2/guild/inviteLink").permitAll()
.antMatchers("/swagger-ui/**").permitAll() .requestMatchers("/swagger-ui/**").permitAll()
.antMatchers("/swagger-ui.html").permitAll() .requestMatchers("/swagger-ui.html").permitAll()
.antMatchers("/v3/api-docs/**").permitAll() .requestMatchers("/v3/api-docs/**").permitAll()
.antMatchers("/actuator/**").permitAll() .requestMatchers("/actuator/**").permitAll()
.anyRequest().authenticated(); .anyRequest().authenticated());
http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
} }
@Bean @Bean
public JwtFilter jwtFilter(){ public JwtFilter jwtFilter() {
return new JwtFilter(); return new JwtFilter();
} }
@Bean @Bean
@Override public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
public AuthenticationManager authenticationManagerBean() throws Exception { return http.getSharedObject(AuthenticationManagerBuilder.class)
return super.authenticationManagerBean(); .build();
} }
} }

View File

@ -58,11 +58,13 @@ public class DiscordOauthService {
try { try {
HttpResponse<String> response = makeFormPost(this.tokenEndpoint, data); HttpResponse<String> response = makeFormPost(this.tokenEndpoint, data);
if (response.statusCode() != 200) { if (response.statusCode() != 200) {
logger.warn("[OAUTH] Invalid response while getting AccessToken: Status Code: " + response.statusCode() + " Body:" + response.body()); logger.warn("[OAUTH] Invalid response while getting AccessToken: Status Code: " + response.statusCode()
+ " Body:" + response.body());
throw new OAuthLoginFail(); throw new OAuthLoginFail();
} }
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
AccessTokenResponse accessTokenResponse = objectMapper.readValue(response.body(), AccessTokenResponse.class); AccessTokenResponse accessTokenResponse = objectMapper.readValue(response.body(),
AccessTokenResponse.class);
return accessTokenResponse.access_token(); return accessTokenResponse.access_token();
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
logger.catching(e); logger.catching(e);
@ -81,7 +83,8 @@ public class DiscordOauthService {
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) { if (response.statusCode() != 200) {
logger.warn("[OAUTH] Invalid response while getting UserInfo: Status Code: " + response.statusCode() + " Body:" + response.body()); logger.warn("[OAUTH] Invalid response while getting UserInfo: Status Code: " + response.statusCode()
+ " Body:" + response.body());
throw new OAuthLoginFail(); throw new OAuthLoginFail();
} }
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
@ -99,49 +102,49 @@ public class DiscordOauthService {
try { try {
HttpResponse<String> response = makeFormPost(this.tokenRevokeEndpoint, data); HttpResponse<String> response = makeFormPost(this.tokenRevokeEndpoint, data);
if (response.statusCode() != 200) { if (response.statusCode() != 200) {
logger.warn("[OAUTH] Invalid response while token revocation: Status Code: " + response.statusCode() + " Body:" + response.body()); logger.warn("[OAUTH] Invalid response while token revocation: Status Code: " + response.statusCode()
+ " Body:" + response.body());
} }
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
logger.catching(e); logger.catching(e);
} }
} }
public record LoginOrRegisterResponse<T>(T response, boolean created) { public record LoginOrRegisterResponse<T>(T response, boolean created) {
} }
public LoginOrRegisterResponse<UserEntity> loginOrRegisterDiscordUser(DiscordOauthUserInfo discordOauthUserInfo) { public LoginOrRegisterResponse<UserEntity> loginOrRegisterDiscordUser(DiscordOauthUserInfo discordOauthUserInfo) {
Optional<UserEntity> optionalUserEntity = userRepository.findByDiscordId(discordOauthUserInfo.id()); Optional<UserEntity> optionalUserEntity = userRepository.findByDiscordId(discordOauthUserInfo.id());
return optionalUserEntity.map( return optionalUserEntity.map(
userEntity -> new LoginOrRegisterResponse<>(userEntity, false)) userEntity -> new LoginOrRegisterResponse<>(userEntity, false))
.orElseGet(() -> { .orElseGet(() -> {
UserEntity created = userRepository.save(new UserEntity(discordOauthUserInfo)); UserEntity created = userRepository.save(new UserEntity(discordOauthUserInfo));
return new LoginOrRegisterResponse<>(created, true); return new LoginOrRegisterResponse<>(created, true);
}); });
} }
public UserEntity updateUserInfo(DiscordOauthUserInfo discordOauthUserInfo, UserEntity userEntity){ public UserEntity updateUserInfo(DiscordOauthUserInfo discordOauthUserInfo, UserEntity userEntity) {
boolean updated = false; boolean updated = false;
if(userEntity.getUsername() == null || !userEntity.getUsername().equals(discordOauthUserInfo.username())){ if (userEntity.getUsername() == null || !userEntity.getUsername().equals(discordOauthUserInfo.username())) {
userEntity.setUsername(discordOauthUserInfo.username()); userEntity.setUsername(discordOauthUserInfo.username());
updated = true; updated = true;
} }
if(userEntity.getDiscriminator() == null || !userEntity.getDiscriminator().equals(discordOauthUserInfo.discriminator())){ if (userEntity.getDiscriminator() == null
|| !userEntity.getDiscriminator().equals(discordOauthUserInfo.discriminator())) {
userEntity.setDiscriminator(discordOauthUserInfo.discriminator()); userEntity.setDiscriminator(discordOauthUserInfo.discriminator());
updated = true; updated = true;
} }
if(userEntity.getAvatar() == null || !userEntity.getAvatar().equals(discordOauthUserInfo.avatar())){ if (userEntity.getAvatar() == null || !userEntity.getAvatar().equals(discordOauthUserInfo.avatar())) {
userEntity.setAvatar(discordOauthUserInfo.avatar()); userEntity.setAvatar(discordOauthUserInfo.avatar());
updated = true; updated = true;
} }
if(updated){ if (updated) {
return userRepository.save(userEntity); return userRepository.save(userEntity);
} }
return userEntity; return userEntity;
} }
private String getFormString(HashMap<String, String> params) { private String getFormString(HashMap<String, String> params) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
boolean first = true; boolean first = true;
@ -157,7 +160,8 @@ public class DiscordOauthService {
return result.toString(); return result.toString();
} }
private HttpResponse<String> makeFormPost(String endpoint, HashMap<String, String> data) throws IOException, InterruptedException { private HttpResponse<String> makeFormPost(String endpoint, HashMap<String, String> data)
throws IOException, InterruptedException {
HttpRequest.BodyPublisher body = HttpRequest.BodyPublishers.ofString(getFormString(data)); HttpRequest.BodyPublisher body = HttpRequest.BodyPublishers.ofString(getFormString(data));
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(tokenEndpoint)) .uri(URI.create(tokenEndpoint))
@ -168,5 +172,4 @@ public class DiscordOauthService {
return client.send(request, HttpResponse.BodyHandlers.ofString()); return client.send(request, HttpResponse.BodyHandlers.ofString());
} }
} }

View File

@ -1,34 +1,33 @@
package net.Broken.Api.Security.Services; package net.Broken.Api.Security.Services;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.UserRepository;
import org.springframework.stereotype.Service;
import java.security.Key;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.UUID; import java.util.UUID;
import javax.crypto.SecretKey;
import org.springframework.stereotype.Service;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.UserRepository;
@Service @Service
public class JwtService { public class JwtService {
private final Key jwtKey; private final SecretKey jwtKey;
private final UserRepository userRepository; private final UserRepository userRepository;
public JwtService(UserRepository userRepository) { public JwtService(UserRepository userRepository) {
this.userRepository = userRepository; this.userRepository = userRepository;
this.jwtKey = Keys.secretKeyFor(SignatureAlgorithm.HS256); this.jwtKey = Jwts.SIG.HS256.key().build();
} }
public String buildJwt(UserEntity user){ public String buildJwt(UserEntity user) {
Date iat = new Date(); Date iat = new Date();
Date nbf = new Date(); Date nbf = new Date();
Calendar expCal = Calendar.getInstance(); Calendar expCal = Calendar.getInstance();
@ -36,33 +35,29 @@ public class JwtService {
Date exp = expCal.getTime(); Date exp = expCal.getTime();
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
return Jwts.builder() return Jwts.builder()
.setSubject(user.getUsername()) .subject(user.getUsername())
.claim("discord_id", user.getDiscordId()) .claim("discord_id", user.getDiscordId())
.claim("avatar", user.getAvatar()) .claim("avatar", user.getAvatar())
.claim("discriminator", user.getDiscriminator()) .claim("discriminator", user.getDiscriminator())
.setId(uuid.toString()) .id(uuid.toString())
.setIssuedAt(iat) .issuedAt(iat)
.setNotBefore(nbf) .notBefore(nbf)
.setExpiration(exp) .expiration(exp)
.signWith(this.jwtKey) .signWith(this.jwtKey)
.compact(); .compact();
} }
public Jws<Claims> verifyAndParseJwt(String token) { public Jws<Claims> verifyAndParseJwt(String token) {
return Jwts.parserBuilder() return Jwts.parser()
.setSigningKey(this.jwtKey) .verifyWith(this.jwtKey)
.build() .build()
.parseClaimsJws(token); .parseSignedClaims(token);
} }
public UserEntity getUserWithJwt(Jws<Claims> jwt) throws NoSuchElementException { public UserEntity getUserWithJwt(Jws<Claims> jwt) throws NoSuchElementException {
String discordId = jwt.getBody().get("discord_id", String.class); String discordId = jwt.getPayload().get("discord_id", String.class);
return userRepository.findByDiscordId(discordId) return userRepository.findByDiscordId(discordId)
.orElseThrow(); .orElseThrow();
} }

View File

@ -9,7 +9,9 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.audio.hooks.ConnectionStatus; import net.dv8tion.jda.api.audio.hooks.ConnectionStatus;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -27,35 +29,35 @@ public class AudioService {
Guild guild = MainBot.jda.getGuildById(guildId); Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(userId); Member member = guild.getMemberById(userId);
AudioChannelUnion channel = guild.getAudioManager().getConnectedChannel();
VoiceChannel channel = guild.getAudioManager().getConnectedChannel();
ConnectionStatus status = guild.getAudioManager().getConnectionStatus(); ConnectionStatus status = guild.getAudioManager().getConnectionStatus();
if (channel != null) { if (channel != null) {
// The user can view the audio status if: // The user can view the audio status if:
// -> He can view the voice channel // -> He can view the voice channel
// -> OR He can *not* view the voice channel, but he is connected to this voice channel // -> OR He can *not* view the voice channel, but he is connected to this voice
// channel
boolean canView = member.hasPermission(channel, Permission.VIEW_CHANNEL) boolean canView = member.hasPermission(channel, Permission.VIEW_CHANNEL)
|| (member.getVoiceState() != null || (member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel); && member.getVoiceState().getChannel() == channel);
GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(guild); GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(guild);
if (canView) { if (canView) {
// The user can interact with the audio if: // The user can interact with the audio if:
// -> He can connect to this voice channel // -> He can connect to this voice channel
// -> OR he is connected to this voice channel // -> OR he is connected to this voice channel
// -> AND He can speak in this voice channel // -> AND He can speak in this voice channel
boolean canInteract = (member.hasPermission(channel, Permission.VOICE_CONNECT) boolean canInteract = (member.hasPermission(channel, Permission.VOICE_CONNECT)
|| member.getVoiceState() != null || member.getVoiceState() != null
&& member.getVoiceState().getChannel() == channel) && member.getVoiceState().getChannel() == channel)
&& member.hasPermission(channel, Permission.VOICE_SPEAK); && member.hasPermission(channel, Permission.VOICE_SPEAK);
boolean stopped = guildAudioBotService.getGuidAudioManager().player.getPlayingTrack() == null; boolean stopped = guildAudioBotService.getGuidAudioManager().player.getPlayingTrack() == null;
PlayBackInfo playBackInfo; PlayBackInfo playBackInfo;
if (!stopped) { if (!stopped) {
boolean paused = guildAudioBotService.getGuidAudioManager().player.isPaused(); boolean paused = guildAudioBotService.getGuidAudioManager().player.isPaused();
long position = guildAudioBotService.getGuidAudioManager().player.getPlayingTrack().getPosition(); long position = guildAudioBotService.getGuidAudioManager().player.getPlayingTrack().getPosition();
UserAudioTrack userAudioTrack = guildAudioBotService.getGuidAudioManager().scheduler.getCurrentPlayingTrack(); UserAudioTrack userAudioTrack = guildAudioBotService.getGuidAudioManager().scheduler
.getCurrentPlayingTrack();
playBackInfo = new PlayBackInfo(paused, false, position, new TrackInfo(userAudioTrack)); playBackInfo = new PlayBackInfo(paused, false, position, new TrackInfo(userAudioTrack));
@ -88,7 +90,6 @@ public class AudioService {
return new ResponseEntity<>(status, HttpStatus.OK); return new ResponseEntity<>(status, HttpStatus.OK);
} }
public ResponseEntity<Status> pause(String guildId, String userId) { public ResponseEntity<Status> pause(String guildId, String userId) {
Guild guild = MainBot.jda.getGuildById(guildId); Guild guild = MainBot.jda.getGuildById(guildId);
GuildAudioBotService.getInstance(guild).pause(); GuildAudioBotService.getInstance(guild).pause();
@ -117,7 +118,8 @@ public class AudioService {
return new ResponseEntity<>(status, HttpStatus.OK); return new ResponseEntity<>(status, HttpStatus.OK);
} }
public ResponseEntity<Status> add(String guildId, String userId, Add body) throws ExecutionException, InterruptedException { public ResponseEntity<Status> add(String guildId, String userId, Add body)
throws ExecutionException, InterruptedException {
Guild guild = MainBot.jda.getGuildById(guildId); Guild guild = MainBot.jda.getGuildById(guildId);
boolean success = GuildAudioBotService.getInstance(guild).loadAndPlaySync(body.url(), userId); boolean success = GuildAudioBotService.getInstance(guild).loadAndPlaySync(body.url(), userId);
if (success) { if (success) {

View File

@ -8,6 +8,9 @@ import net.Broken.MainBot;
import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
@ -24,8 +27,7 @@ public class GuildService {
boolean canManage = guild.getMember(discordUser).hasPermission( boolean canManage = guild.getMember(discordUser).hasPermission(
Permission.MANAGE_SERVER, Permission.MANAGE_SERVER,
Permission.MANAGE_PERMISSIONS, Permission.MANAGE_PERMISSIONS,
Permission.MANAGE_CHANNEL Permission.MANAGE_CHANNEL);
);
guildList.add(new Guild(guild.getId(), guild.getName(), guild.getIconUrl(), canManage)); guildList.add(new Guild(guild.getId(), guild.getName(), guild.getIconUrl(), canManage));
} }
return guildList; return guildList;
@ -35,7 +37,7 @@ public class GuildService {
net.dv8tion.jda.api.entities.Guild guild = MainBot.jda.getGuildById(guildId); net.dv8tion.jda.api.entities.Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(userId); Member member = guild.getMemberById(userId);
List<Channel> voiceChannels = new ArrayList<>(); List<Channel> voiceChannels = new ArrayList<>();
for (net.dv8tion.jda.api.entities.VoiceChannel voiceChannel : guild.getVoiceChannels()) { for (VoiceChannel voiceChannel : guild.getVoiceChannels()) {
if (member.hasPermission(voiceChannel, Permission.VIEW_CHANNEL)) { if (member.hasPermission(voiceChannel, Permission.VIEW_CHANNEL)) {
voiceChannels.add(new Channel(voiceChannel.getId(), voiceChannel.getName())); voiceChannels.add(new Channel(voiceChannel.getId(), voiceChannel.getName()));
} }
@ -47,7 +49,7 @@ public class GuildService {
net.dv8tion.jda.api.entities.Guild guild = MainBot.jda.getGuildById(guildId); net.dv8tion.jda.api.entities.Guild guild = MainBot.jda.getGuildById(guildId);
Member member = guild.getMemberById(userId); Member member = guild.getMemberById(userId);
List<Channel> voiceChannels = new ArrayList<>(); List<Channel> voiceChannels = new ArrayList<>();
for (net.dv8tion.jda.api.entities.TextChannel textChannel : guild.getTextChannels()) { for (TextChannel textChannel : guild.getTextChannels()) {
if (member.hasPermission(textChannel, Permission.VIEW_CHANNEL)) { if (member.hasPermission(textChannel, Permission.VIEW_CHANNEL)) {
voiceChannels.add(new Channel(textChannel.getId(), textChannel.getName())); voiceChannels.add(new Channel(textChannel.getId(), textChannel.getName()));
} }
@ -66,9 +68,9 @@ public class GuildService {
return roles; return roles;
} }
public String getInviteLink() {
public String getInviteLink(){ return MainBot.jda.setRequiredScopes("applications.commands")
return MainBot.jda.setRequiredScopes("applications.commands").getInviteUrl(Permission.getPermissions(1644971949399L)); .getInviteUrl(Permission.getPermissions(1644971949399L));
} }
} }

View File

@ -19,7 +19,6 @@ public class SettingService {
public final GuildPreferenceRepository preferenceRepository; public final GuildPreferenceRepository preferenceRepository;
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
public SettingService(GuildPreferenceRepository preferenceRepository) { public SettingService(GuildPreferenceRepository preferenceRepository) {
this.preferenceRepository = preferenceRepository; this.preferenceRepository = preferenceRepository;
} }
@ -28,7 +27,6 @@ public class SettingService {
return new SettingDescriptionBuilder().build(); return new SettingDescriptionBuilder().build();
} }
public List<Value> getValues(String guildId) { public List<Value> getValues(String guildId) {
GuildPreferenceEntity pref = preferenceRepository.findByGuildId(guildId).orElseGet(() -> { GuildPreferenceEntity pref = preferenceRepository.findByGuildId(guildId).orElseGet(() -> {
logger.info("[API] : Generate default guild pref"); logger.info("[API] : Generate default guild pref");
@ -37,7 +35,7 @@ public class SettingService {
return new SettingValueBuilder(pref).build(); return new SettingValueBuilder(pref).build();
} }
public GuildPreferenceEntity saveValue(String guildId, List<Value> values){ public GuildPreferenceEntity saveValue(String guildId, List<Value> values) {
GuildPreferenceEntity pref = preferenceRepository.findByGuildId(guildId).orElseGet(() -> { GuildPreferenceEntity pref = preferenceRepository.findByGuildId(guildId).orElseGet(() -> {
logger.info("[API] : Generate default guild pref"); logger.info("[API] : Generate default guild pref");
return preferenceRepository.save(GuildPreferenceEntity.getDefault(guildId)); return preferenceRepository.save(GuildPreferenceEntity.getDefault(guildId));

View File

@ -1,14 +1,17 @@
package net.Broken.Audio; package net.Broken.Audio;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.playback.MutableAudioFrame;
import net.dv8tion.jda.api.audio.AudioSendHandler;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.playback.MutableAudioFrame;
import net.dv8tion.jda.api.audio.AudioSendHandler;
/** /**
* This is a wrapper around AudioPlayer which makes it behave as an AudioSendHandler for JDA. As JDA calls canProvide * This is a wrapper around AudioPlayer which makes it behave as an
* before every call to provide20MsAudio(), we pull the frame in canProvide() and use the frame we already pulled in * AudioSendHandler for JDA. As JDA calls canProvide
* before every call to provide20MsAudio(), we pull the frame in canProvide()
* and use the frame we already pulled in
* provide20MsAudio(). * provide20MsAudio().
*/ */
public class AudioPlayerSendHandler implements AudioSendHandler { public class AudioPlayerSendHandler implements AudioSendHandler {

View File

@ -24,17 +24,19 @@ import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import net.Broken.Tools.EmbedMessageUtils; import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Emoji;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel;
import net.dv8tion.jda.api.events.interaction.GenericInteractionCreateEvent; import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.components.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
public class GuildAudioBotService { public class GuildAudioBotService {
@ -47,7 +49,7 @@ public class GuildAudioBotService {
/** /**
* Extrem limit for playlist * Extrem limit for playlist
*/ */
private final int listExtremLimit = 300; private static final int LIST_EXTREM_LIMIT = 300;
private final Guild guild; private final Guild guild;
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
@ -66,9 +68,7 @@ public class GuildAudioBotService {
} }
public static GuildAudioBotService getInstance(Guild guild) { public static GuildAudioBotService getInstance(Guild guild) {
if (!INSTANCES.containsKey(guild)) { INSTANCES.computeIfAbsent(guild, k -> new GuildAudioBotService(guild));
INSTANCES.put(guild, new GuildAudioBotService(guild));
}
return INSTANCES.get(guild); return INSTANCES.get(guild);
} }
@ -80,13 +80,14 @@ public class GuildAudioBotService {
* @param playlistLimit Limit of playlist * @param playlistLimit Limit of playlist
* @param onHead True for adding audio track on top of playlist * @param onHead True for adding audio track on top of playlist
*/ */
public void loadAndPlay(SlashCommandEvent event, VoiceChannel voiceChannel, final String trackUrl, int playlistLimit, boolean onHead) { public void loadAndPlay(SlashCommandInteractionEvent event, AudioChannel voiceChannel, final String trackUrl,
int playlistLimit, boolean onHead) {
audioPlayerManager.loadItemOrdered(guildAudioManager, trackUrl, new AudioLoadResultHandler() { audioPlayerManager.loadItemOrdered(guildAudioManager, trackUrl, new AudioLoadResultHandler() {
@Override @Override
public void trackLoaded(AudioTrack track) { public void trackLoaded(AudioTrack track) {
logger.info("[" + guild + "] Single Track detected!"); logger.info("[{}] Single Track detected!", guild.getName());
UserAudioTrack uat = new UserAudioTrack(event.getUser(), track); UserAudioTrack uat = new UserAudioTrack(event.getUser(), track);
Message message = new MessageBuilder() MessageCreateData message = new MessageCreateBuilder()
.setEmbeds(EmbedMessageUtils.getMusicAdded(track.getInfo(), event.getMember(), -1)) .setEmbeds(EmbedMessageUtils.getMusicAdded(track.getInfo(), event.getMember(), -1))
.build(); .build();
clearLastButton(); clearLastButton();
@ -96,10 +97,10 @@ public class GuildAudioBotService {
@Override @Override
public void playlistLoaded(AudioPlaylist playlist) { public void playlistLoaded(AudioPlaylist playlist) {
logger.info("[" + guild + "] Playlist detected! Limit: " + playlistLimit); logger.info("[{}] Playlist detected! Limit: {}", guild, playlistLimit);
AudioTrack firstTrack = playlist.getSelectedTrack(); AudioTrack firstTrack = playlist.getSelectedTrack();
int size = Math.min(playlist.getTracks().size(), playlistLimit); int size = Math.min(playlist.getTracks().size(), playlistLimit);
Message message = new MessageBuilder() MessageCreateData message = new MessageCreateBuilder()
.setEmbeds(EmbedMessageUtils.getMusicAdded(firstTrack.getInfo(), event.getMember(), size)) .setEmbeds(EmbedMessageUtils.getMusicAdded(firstTrack.getInfo(), event.getMember(), size))
.build(); .build();
clearLastButton(); clearLastButton();
@ -109,16 +110,18 @@ public class GuildAudioBotService {
@Override @Override
public void noMatches() { public void noMatches() {
logger.warn("[" + guild + "] Cant find media!"); logger.warn("[{}] Cant find media!", guild);
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Video not found !")).build(); MessageCreateData message = new MessageCreateBuilder()
.setEmbeds(EmbedMessageUtils.getMusicError("Video not found !")).build();
event.getHook().setEphemeral(true).sendMessage(message).queue(); event.getHook().setEphemeral(true).sendMessage(message).queue();
} }
@Override @Override
public void loadFailed(FriendlyException exception) { public void loadFailed(FriendlyException exception) {
logger.error("[" + guild + "] Can't load media!"); logger.error("[{}] Can't load media!", guild);
logger.error(exception.getMessage()); logger.error(exception.getMessage());
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Playback error !")).build(); MessageCreateData message = new MessageCreateBuilder()
.setEmbeds(EmbedMessageUtils.getMusicError("Playback error !")).build();
event.getHook().setEphemeral(true).sendMessage(message).queue(); event.getHook().setEphemeral(true).sendMessage(message).queue();
} }
}); });
@ -126,44 +129,44 @@ public class GuildAudioBotService {
public boolean loadAndPlaySync(String trackUrl, String userId) throws ExecutionException, InterruptedException { public boolean loadAndPlaySync(String trackUrl, String userId) throws ExecutionException, InterruptedException {
Member member = guild.getMemberById(userId); Member member = guild.getMemberById(userId);
VoiceChannel playedChanel = guild.getAudioManager().getConnectedChannel(); AudioChannelUnion playedChanel = guild.getAudioManager().getConnectedChannel();
final String uuid = UUID.randomUUID().toString(); final String uuid = UUID.randomUUID().toString();
Future<Void> future = audioPlayerManager.loadItemOrdered(guildAudioManager, trackUrl, new AudioLoadResultHandler() { Future<Void> future = audioPlayerManager.loadItemOrdered(guildAudioManager, trackUrl,
@Override new AudioLoadResultHandler() {
public void trackLoaded(AudioTrack track) { @Override
logger.info("[" + guild + "] Auto add " + track.getInfo().title + " to playlist."); public void trackLoaded(AudioTrack track) {
UserAudioTrack userAudioTrack = new UserAudioTrack(member.getUser(), track); logger.info("[{}] Auto add {} to playlist.", guild, track.getInfo().title);
play(guild, playedChanel, guildAudioManager, userAudioTrack, true); UserAudioTrack userAudioTrack = new UserAudioTrack(member.getUser(), track);
addStatus.put(uuid, true); play(guild, playedChanel, guildAudioManager, userAudioTrack, true);
} addStatus.put(uuid, true);
}
@Override @Override
public void playlistLoaded(AudioPlaylist playlist) { public void playlistLoaded(AudioPlaylist playlist) {
AudioTrack track = playlist.getTracks().get(0); AudioTrack track = playlist.getTracks().get(0);
logger.info("[" + guild + "] Auto add " + track.getInfo().title + " to playlist."); logger.info("[{}] Auto add {} to playlist.", guild, track.getInfo().title);
UserAudioTrack userAudioTrack = new UserAudioTrack(member.getUser(), track); UserAudioTrack userAudioTrack = new UserAudioTrack(member.getUser(), track);
play(guild, playedChanel, guildAudioManager, userAudioTrack, true); play(guild, playedChanel, guildAudioManager, userAudioTrack, true);
addStatus.put(uuid, true); addStatus.put(uuid, true);
} }
@Override @Override
public void noMatches() { public void noMatches() {
logger.warn("[" + guild + "] Track not found: " + trackUrl); logger.warn("[{}] Track not found: {}", guild, trackUrl);
addStatus.put(uuid, false); addStatus.put(uuid, false);
} }
@Override @Override
public void loadFailed(FriendlyException exception) { public void loadFailed(FriendlyException exception) {
logger.error("[" + guild + "] Cant load media!"); logger.error("[{}] Cant load media!", guild);
logger.error(exception.getMessage()); logger.error(exception.getMessage());
addStatus.put(uuid, false); addStatus.put(uuid, false);
} }
}); });
future.get(); future.get();
return addStatus.remove(uuid); return addStatus.remove(uuid);
} }
/** /**
* Load playlist to playlist * Load playlist to playlist
* *
@ -174,7 +177,7 @@ public class GuildAudioBotService {
*/ */
public void playListLoader(AudioPlaylist playlist, int playlistLimit, User user, boolean onHead) { public void playListLoader(AudioPlaylist playlist, int playlistLimit, User user, boolean onHead) {
VoiceChannel playedChanel = guild.getAudioManager().getConnectedChannel(); AudioChannelUnion playedChanel = guild.getAudioManager().getConnectedChannel();
List<AudioTrack> tracks = playlist.getTracks(); List<AudioTrack> tracks = playlist.getTracks();
if (onHead) if (onHead)
Collections.reverse(tracks); Collections.reverse(tracks);
@ -183,13 +186,12 @@ public class GuildAudioBotService {
for (AudioTrack track : playlist.getTracks()) { for (AudioTrack track : playlist.getTracks()) {
UserAudioTrack uat = new UserAudioTrack(user, track); UserAudioTrack uat = new UserAudioTrack(user, track);
play(guild, playedChanel, guildAudioManager, uat, onHead); play(guild, playedChanel, guildAudioManager, uat, onHead);
if ((playlistLimit != -1 && i >= playlistLimit) || i > listExtremLimit) if ((playlistLimit != -1 && i >= playlistLimit) || i > LIST_EXTREM_LIMIT)
break; break;
i++; i++;
} }
} }
/** /**
* Add single track to playlist, auto-connect if not connected to vocal chanel * Add single track to playlist, auto-connect if not connected to vocal chanel
* *
@ -199,7 +201,8 @@ public class GuildAudioBotService {
* @param track Track to add to playlist * @param track Track to add to playlist
* @param onHead True for adding audio track on top of playlist * @param onHead True for adding audio track on top of playlist
*/ */
public void play(Guild guild, VoiceChannel channel, GuildAudioManager musicManager, UserAudioTrack track, boolean onHead) { public void play(Guild guild, AudioChannel channel, GuildAudioManager musicManager, UserAudioTrack track,
boolean onHead) {
if (!guild.getAudioManager().isConnected()) if (!guild.getAudioManager().isConnected())
guild.getAudioManager().openAudioConnection(channel); guild.getAudioManager().openAudioConnection(channel);
if (!onHead) if (!onHead)
@ -208,87 +211,88 @@ public class GuildAudioBotService {
musicManager.scheduler.addNext(track); musicManager.scheduler.addNext(track);
} }
public void add(SlashCommandEvent event, String url, int playListLimit, boolean onHead) { public void add(SlashCommandInteractionEvent event, String url, int playListLimit, boolean onHead) {
if (guild.getAudioManager().isConnected()) { if (guild.getAudioManager().isConnected()) {
loadAndPlay(event, guild.getAudioManager().getConnectedChannel(), url, playListLimit, onHead); loadAndPlay(event, guild.getAudioManager().getConnectedChannel(), url, playListLimit, onHead);
} else { } else {
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Not connected to vocal chanel !")).build(); MessageCreateData message = new MessageCreateBuilder()
.setEmbeds(EmbedMessageUtils.getMusicError("Not connected to vocal chanel !")).build();
event.getHook().setEphemeral(true).sendMessage(message).queue(); event.getHook().setEphemeral(true).sendMessage(message).queue();
} }
} }
public void connect(VoiceChannel voiceChannel) { public void connect(AudioChannel voiceChannel) {
guild.getAudioManager().openAudioConnection(voiceChannel); guild.getAudioManager().openAudioConnection(voiceChannel);
} }
public void pause(GenericInteractionCreateEvent event) { public void pause(InteractionHook hook) {
pause(); pause();
Message message = new MessageBuilder().setEmbeds( MessageCreateData message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":pause_button: Playback paused") .setTitle(":pause_button: Playback paused")
.setColor(Color.green) .setColor(Color.green)))
)).build(); .build();
clearLastButton(); clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = hook.sendMessage(message).addActionRow(getActionButton()).complete();
} }
public void pause() { public void pause() {
guildAudioManager.scheduler.pause(); guildAudioManager.scheduler.pause();
} }
public void resume(GenericInteractionCreateEvent event) { public void resume(InteractionHook hook) {
Message message; MessageCreateData message;
if (guildAudioManager.player.getPlayingTrack() == null) { if (guildAudioManager.player.getPlayingTrack() == null) {
message = new MessageBuilder().setEmbeds( message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":warning: Nothing to play, playlist is empty !") .setTitle(":warning: Nothing to play, playlist is empty !")
.setColor(Color.green) .setColor(Color.green)))
)).build(); .build();
} else { } else {
resume(); resume();
message = new MessageBuilder().setEmbeds( message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":arrow_forward: Playback resumed") .setTitle(":arrow_forward: Playback resumed")
.setColor(Color.green) .setColor(Color.green)))
)).build(); .build();
} }
clearLastButton(); clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = hook.sendMessage(message).addActionRow(getActionButton()).complete();
} }
public void resume() { public void resume() {
guildAudioManager.scheduler.resume(); guildAudioManager.scheduler.resume();
} }
public void skipTrack(GenericInteractionCreateEvent event) { public void skipTrack(InteractionHook hook) {
skipTrack(); skipTrack();
Message message = new MessageBuilder().setEmbeds( MessageCreateData message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":track_next: Next Track") .setTitle(":track_next: Next Track")
.setColor(Color.green) .setColor(Color.green)))
)).build(); .build();
clearLastButton(); clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = hook.sendMessage(message).addActionRow(getActionButton()).complete();
} }
public void skipTrack() { public void skipTrack() {
guildAudioManager.scheduler.nextTrack(); guildAudioManager.scheduler.nextTrack();
} }
public void stop(GenericInteractionCreateEvent event) { public void stop(InteractionHook hook) {
stop(); stop();
Message message = new MessageBuilder().setEmbeds( MessageCreateData message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":stop_button: Playback stopped") .setTitle(":stop_button: Playback stopped")
.setColor(Color.green) .setColor(Color.green)))
)).build(); .build();
clearLastButton(); clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = hook.sendMessage(message).addActionRow(getActionButton()).complete();
} }
@ -298,16 +302,16 @@ public class GuildAudioBotService {
clearLastButton(); clearLastButton();
} }
public void disconnect(GenericInteractionCreateEvent event) { public void disconnect(InteractionHook hook) {
disconnect(); disconnect();
Message message = new MessageBuilder().setEmbeds( MessageCreateData message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":eject: Disconnected") .setTitle(":eject: Disconnected")
.setColor(Color.green) .setColor(Color.green)))
)).build(); .build();
clearLastButton(); clearLastButton();
event.getHook().sendMessage(message).queue(); hook.sendMessage(message).queue();
} }
public void disconnect() { public void disconnect() {
@ -316,24 +320,26 @@ public class GuildAudioBotService {
guild.getAudioManager().closeAudioConnection(); guild.getAudioManager().closeAudioConnection();
clearLastButton(); clearLastButton();
} }
public void info(GenericInteractionCreateEvent event) {
public void info(InteractionHook hook) {
AudioTrackInfo info = guildAudioManager.scheduler.getInfo(); AudioTrackInfo info = guildAudioManager.scheduler.getInfo();
UserAudioTrack userAudioTrack = guildAudioManager.scheduler.getCurrentPlayingTrack(); UserAudioTrack userAudioTrack = guildAudioManager.scheduler.getCurrentPlayingTrack();
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicInfo(info, userAudioTrack)).build(); MessageCreateData message = new MessageCreateBuilder()
.setEmbeds(EmbedMessageUtils.getMusicInfo(info, userAudioTrack)).build();
clearLastButton(); clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = hook.sendMessage(message).addActionRow(getActionButton()).complete();
} }
public void flush(GenericInteractionCreateEvent event) { public void flush(InteractionHook hook) {
guildAudioManager.scheduler.flush(); guildAudioManager.scheduler.flush();
Message message = new MessageBuilder().setEmbeds( MessageCreateData message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":wastebasket: Playlist flushed") .setTitle(":wastebasket: Playlist flushed")
.setColor(Color.green) .setColor(Color.green)))
)).build(); .build();
clearLastButton(); clearLastButton();
lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = hook.sendMessage(message).addActionRow(getActionButton()).complete();
} }
/** /**
@ -341,18 +347,18 @@ public class GuildAudioBotService {
* *
* @param event * @param event
*/ */
public void list(GenericInteractionCreateEvent event) { public void list(InteractionHook hook) {
List<UserAudioTrack> list = guildAudioManager.scheduler.getList(); List<UserAudioTrack> list = guildAudioManager.scheduler.getList();
if (list.size() == 0) { if (list.isEmpty()) {
Message message = new MessageBuilder().setEmbeds( MessageCreateData message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":scroll: Playlist") .setTitle(":scroll: Playlist")
.setColor(Color.green) .setColor(Color.green)
.setDescription("Oh no ! The playlist is empty !") .setDescription("Oh no ! The playlist is empty !")))
)).build(); .build();
event.getHook().sendMessage(message).queue(); hook.sendMessage(message).queue();
} else { } else {
StringBuilder resp = new StringBuilder(); StringBuilder resp = new StringBuilder();
int i = 0; int i = 0;
@ -370,14 +376,14 @@ public class GuildAudioBotService {
} }
i++; i++;
} }
Message message = new MessageBuilder().setEmbeds( MessageCreateData message = new MessageCreateBuilder().setEmbeds(
EmbedMessageUtils.buildStandar( EmbedMessageUtils.buildStandar(
new EmbedBuilder() new EmbedBuilder()
.setTitle(":scroll: Playlist") .setTitle(":scroll: Playlist")
.setColor(Color.green) .setColor(Color.green)
.setDescription(resp.toString()) .setDescription(resp.toString())))
)).build(); .build();
event.getHook().sendMessage(message).queue(); hook.sendMessage(message).queue();
} }
} }
@ -390,7 +396,6 @@ public class GuildAudioBotService {
return guildAudioManager; return guildAudioManager;
} }
public void clearLastButton() { public void clearLastButton() {
if (lastMessageWithButton != null) { if (lastMessageWithButton != null) {
this.lastMessageWithButton.editMessageComponents(new ArrayList<>()).queue(); this.lastMessageWithButton.editMessageComponents(new ArrayList<>()).queue();
@ -401,10 +406,10 @@ public class GuildAudioBotService {
public void updateLastButton() { public void updateLastButton() {
if (lastMessageWithButton != null) if (lastMessageWithButton != null)
lastMessageWithButton = lastMessageWithButton.editMessageComponents(ActionRow.of(getActionButton())).complete(); lastMessageWithButton = lastMessageWithButton.editMessageComponents(ActionRow.of(getActionButton()))
.complete();
} }
private List<Button> getActionButton() { private List<Button> getActionButton() {
ArrayList<Button> buttonArrayList = new ArrayList<>(); ArrayList<Button> buttonArrayList = new ArrayList<>();
if (guildAudioManager.player.getPlayingTrack() == null) { if (guildAudioManager.player.getPlayingTrack() == null) {

View File

@ -19,7 +19,8 @@ import net.Broken.MainBot;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
/** /**
* This class schedules tracks for the audio player. It contains the queue of tracks. * This class schedules tracks for the audio player. It contains the queue of
* tracks.
*/ */
public class TrackScheduler extends AudioEventAdapter { public class TrackScheduler extends AudioEventAdapter {
private final AudioPlayer player; private final AudioPlayer player;
@ -46,8 +47,10 @@ public class TrackScheduler extends AudioEventAdapter {
* @param track The track to play or add to queue. * @param track The track to play or add to queue.
*/ */
public void queue(UserAudioTrack track) { public void queue(UserAudioTrack track) {
// Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If // Calling startTrack with the noInterrupt set to true will start the track only
// something is playing, it returns false and does nothing. In that case the player was already playing so this // if nothing is currently playing. If
// something is playing, it returns false and does nothing. In that case the
// player was already playing so this
// track goes to the queue instead. // track goes to the queue instead.
if (track.getSubmittedUser() != MainBot.jda.getSelfUser()) { if (track.getSubmittedUser() != MainBot.jda.getSelfUser()) {
logger.debug("[" + guild + "] Flush history"); logger.debug("[" + guild + "] Flush history");
@ -66,8 +69,10 @@ public class TrackScheduler extends AudioEventAdapter {
* @param track * @param track
*/ */
public void addNext(UserAudioTrack track) { public void addNext(UserAudioTrack track) {
// Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If // Calling startTrack with the noInterrupt set to true will start the track only
// something is playing, it returns false and does nothing. In that case the player was already playing so this // if nothing is currently playing. If
// something is playing, it returns false and does nothing. In that case the
// player was already playing so this
// track goes to the queue instead. // track goes to the queue instead.
if (!player.startTrack(track.getAudioTrack(), true)) { if (!player.startTrack(track.getAudioTrack(), true)) {
queue.addFirst(track); queue.addFirst(track);
@ -134,10 +139,12 @@ public class TrackScheduler extends AudioEventAdapter {
* Start the next track, stopping the current one if it is playing. * Start the next track, stopping the current one if it is playing.
*/ */
public void nextTrack() { public void nextTrack() {
// Start the next track, regardless of if something is already playing or not. In case queue was empty, we are // Start the next track, regardless of if something is already playing or not.
// giving null to startTrack, which is a valid argument and will simply stop the player. // In case queue was empty, we are
// giving null to startTrack, which is a valid argument and will simply stop the
// player.
UserAudioTrack track = queue.poll(); UserAudioTrack track = queue.poll();
if (track != null){ if (track != null) {
this.currentPlayingTrack = track; this.currentPlayingTrack = track;
player.startTrack(track.getAudioTrack(), false); player.startTrack(track.getAudioTrack(), false);
} }
@ -145,17 +152,17 @@ public class TrackScheduler extends AudioEventAdapter {
@Override @Override
public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) {
// Only start the next track if the end reason is suitable for it (FINISHED or LOAD_FAILED) // Only start the next track if the end reason is suitable for it (FINISHED or
// LOAD_FAILED)
if (endReason.mayStartNext) { if (endReason.mayStartNext) {
if(queue.isEmpty()){ if (queue.isEmpty()) {
logger.debug("[" + guild.getName() + "] End of track, Playlist empty."); logger.debug("[" + guild.getName() + "] End of track, Playlist empty.");
GuildAudioBotService.getInstance(guild).updateLastButton(); GuildAudioBotService.getInstance(guild).updateLastButton();
}else{ } else {
logger.debug("[" + guild.getName() + "] End of track, start next."); logger.debug("[" + guild.getName() + "] End of track, start next.");
nextTrack(); nextTrack();
} }
} }
} }

View File

@ -1,13 +1,11 @@
package net.Broken; package net.Broken;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
@ConfigurationProperties(prefix = "discord.bot") @ConfigurationProperties(prefix = "discord.bot")
@ConstructorBinding public record BotConfigLoader(
public record BotConfigLoader ( String token,
String token, String url,
String url, String mode,
String mode, String randomApiKey) {
String randomApiKey }
){}

View File

@ -1,5 +1,13 @@
package net.Broken; package net.Broken;
import java.awt.Color;
import java.util.HashMap;
import java.util.Optional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import net.Broken.Audio.GuildAudioBotService; import net.Broken.Audio.GuildAudioBotService;
import net.Broken.DB.Entity.GuildPreferenceEntity; import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository; import net.Broken.DB.Repository.GuildPreferenceRepository;
@ -7,28 +15,21 @@ import net.Broken.Tools.AutoVoiceChannel;
import net.Broken.Tools.EmbedMessageUtils; import net.Broken.Tools.EmbedMessageUtils;
import net.Broken.Tools.UserManager.Stats.UserStatsUtils; import net.Broken.Tools.UserManager.Stats.UserStatsUtils;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.ReadyEvent; import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceJoinEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMoveEvent; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.events.interaction.ButtonClickEvent;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.session.ReadyEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.apache.logging.log4j.LogManager; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import org.apache.logging.log4j.Logger; import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationContext;
import java.awt.*;
import java.util.HashMap;
import java.util.Optional;
/** /**
* Bot Listener * Bot Listener
@ -50,27 +51,27 @@ public class BotListener extends ListenerAdapter {
logger.info("Connection success"); logger.info("Connection success");
} }
@Override @Override
public void onGuildMemberJoin(GuildMemberJoinEvent event) { public void onGuildMemberJoin(GuildMemberJoinEvent event) {
GuildPreferenceEntity guildPref = getPreference(event.getGuild()); GuildPreferenceEntity guildPref = getPreference(event.getGuild());
if (guildPref.isDefaultRole()) { if (guildPref.isDefaultRole()) {
logger.info("[" + event.getGuild().getName() + "] : " + event.getUser().getName() + " join the guild, adding default role !"); logger.info("[{}] : {} join the guild, adding default role !", event.getGuild().getName(),
Role default_role = event.getGuild().getRoleById(guildPref.getDefaultRoleId()); event.getUser().getName());
if (default_role != null) { Role defaultRole = event.getGuild().getRoleById(guildPref.getDefaultRoleId());
event.getGuild().addRoleToMember(event.getMember(), default_role).queue(); if (defaultRole != null) {
event.getGuild().addRoleToMember(event.getMember(), defaultRole).queue();
} else { } else {
logger.fatal("[" + event.getGuild().getName() + "] : Default role is null !"); logger.fatal("[{}] : Default role is null !", event.getGuild().getName());
} }
} }
if (guildPref.isWelcome()) { if (guildPref.isWelcome()) {
TextChannel chanel = event.getGuild().getTextChannelById(guildPref.getWelcomeChanelID()); TextChannel chanel = event.getGuild().getTextChannelById(guildPref.getWelcomeChanelID());
if (chanel != null) { if (chanel != null) {
String message = guildPref.getWelcomeMessage().replaceAll("@name", event.getMember().getAsMention()); String message = guildPref.getWelcomeMessage().replace("@name", event.getMember().getAsMention());
logger.debug(message); logger.debug(message);
chanel.sendMessage(message).queue(); chanel.sendMessage(message).queue();
} else { } else {
logger.fatal("[" + event.getGuild().getName() + "] : Welcome chanel is null !"); logger.fatal("[{}] : Welcome chanel is null !", event.getGuild().getName());
} }
} }
@ -79,61 +80,55 @@ public class BotListener extends ListenerAdapter {
@Override @Override
public void onGuildMemberRoleRemove(GuildMemberRoleRemoveEvent event) { public void onGuildMemberRoleRemove(GuildMemberRoleRemoveEvent event) {
GuildPreferenceEntity guildPref = getPreference(event.getGuild()); GuildPreferenceEntity guildPref = getPreference(event.getGuild());
if (guildPref.isDefaultRole()) { if (guildPref.isDefaultRole() && event.getMember().getRoles().isEmpty()) {
if (event.getMember().getRoles().size() == 0) { logger.info("[{}] : {} have no roles, reset to default !", event.getGuild().getName(),
logger.info("[" + event.getGuild().getName() + "] : " + event.getUser().getName() + " have no roles, reset to default !"); event.getUser().getName());
Role default_role = event.getGuild().getRoleById(guildPref.getDefaultRoleId()); Role defaultRole = event.getGuild().getRoleById(guildPref.getDefaultRoleId());
if (default_role == null) { if (defaultRole == null) {
logger.fatal("[" + event.getGuild().getName() + "] : Default role is null !"); logger.fatal("[{}] : Default role is null !", event.getGuild().getName());
return; return;
}
event.getGuild().addRoleToMember(event.getMember(), default_role).queue();
} }
event.getGuild().addRoleToMember(event.getMember(), defaultRole).queue();
} }
} }
@Override @Override
public void onGuildVoiceJoin(GuildVoiceJoinEvent event) { public void onGuildVoiceUpdate(GuildVoiceUpdateEvent event) {
super.onGuildVoiceJoin(event); super.onGuildVoiceUpdate(event);
if (!event.getMember().getUser().isBot()) { // Disconnect
if (event.getChannelJoined() == null) {
if (event.getGuild().getAudioManager().isConnected()) {
logger.trace("User disconnected from voice channel.");
if (event.getGuild().getAudioManager().getConnectedChannel().getMembers().size() == 1) {
logger.debug("I'm alone, close audio connection.");
GuildAudioBotService.getInstance(event.getGuild()).stop();
}
} else if (event.getMember().getUser() == MainBot.jda.getSelfUser()) {
GuildAudioBotService.getInstance(event.getGuild()).clearLastButton();
}
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.leave(event.getChannelLeft());
}
// Connect
else if (event.getChannelLeft() == null && !event.getMember().getUser().isBot()) {
UserStatsUtils userStatsUtils = UserStatsUtils.getINSTANCE(); UserStatsUtils userStatsUtils = UserStatsUtils.getINSTANCE();
if (!userStatsUtils.runningCounters.containsKey(event.getMember().getId())) { if (!userStatsUtils.runningCounters.containsKey(event.getMember().getId())) {
UserStatsUtils.VoicePresenceCounter temp = new UserStatsUtils.VoicePresenceCounter(event.getMember()); UserStatsUtils.VoicePresenceCounter temp = new UserStatsUtils.VoicePresenceCounter(
event.getMember());
temp.start(); temp.start();
userStatsUtils.runningCounters.put(event.getMember().getId(), temp); userStatsUtils.runningCounters.put(event.getMember().getId(), temp);
} }
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild()); AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.join(event.getChannelJoined()); autoVoiceChannel.join(event.getChannelJoined());
} }
} // Move
else {
@Override AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
public void onGuildVoiceLeave(GuildVoiceLeaveEvent event) { autoVoiceChannel.leave(event.getChannelLeft());
super.onGuildVoiceLeave(event); autoVoiceChannel.join(event.getChannelJoined());
if (event.getGuild().getAudioManager().isConnected()) {
logger.trace("User disconnected from voice channel.");
if (event.getGuild().getAudioManager().getConnectedChannel().getMembers().size() == 1) {
logger.debug("I'm alone, close audio connection.");
GuildAudioBotService.getInstance(event.getGuild()).stop();
}
} else if (event.getMember().getUser() == MainBot.jda.getSelfUser()) {
GuildAudioBotService.getInstance(event.getGuild()).clearLastButton();
} }
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.leave(event.getChannelLeft());
}
@Override
public void onGuildVoiceMove(@NotNull GuildVoiceMoveEvent event) {
super.onGuildVoiceMove(event);
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.leave(event.getChannelLeft());
autoVoiceChannel.join(event.getChannelJoined());
} }
@Override @Override
@ -144,23 +139,23 @@ public class BotListener extends ListenerAdapter {
} }
@Override @Override
public void onButtonClick(@NotNull ButtonClickEvent event) { public void onButtonInteraction(ButtonInteractionEvent event) {
super.onButtonClick(event); super.onButtonInteraction(event);
event.deferReply().queue(); event.deferReply().queue();
GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(event.getGuild()); GuildAudioBotService guildAudioBotService = GuildAudioBotService.getInstance(event.getGuild());
switch (event.getComponentId()) { switch (event.getComponentId()) {
case "pause" -> guildAudioBotService.pause(event); case "pause" -> guildAudioBotService.pause(event.getHook());
case "play" -> guildAudioBotService.resume(event); case "play" -> guildAudioBotService.resume(event.getHook());
case "next" -> guildAudioBotService.skipTrack(event); case "next" -> guildAudioBotService.skipTrack(event.getHook());
case "stop" -> guildAudioBotService.stop(event); case "stop" -> guildAudioBotService.stop(event.getHook());
case "disconnect" -> guildAudioBotService.disconnect(event); case "disconnect" -> guildAudioBotService.disconnect(event.getHook());
} }
} }
@Override @Override
public void onSlashCommand(@NotNull SlashCommandEvent event) { public void onSlashCommandInteraction(SlashCommandInteractionEvent event) {
super.onSlashCommandInteraction(event);
HashMap<String, SlashCommand> commands = MainBot.slashCommands; HashMap<String, SlashCommand> commands = MainBot.slashCommands;
super.onSlashCommand(event);
if (commands.containsKey(event.getName())) { if (commands.containsKey(event.getName())) {
SlashCommand commandRunner = commands.get(event.getName()); SlashCommand commandRunner = commands.get(event.getName());
// It's form private message // It's form private message
@ -170,18 +165,16 @@ public class BotListener extends ListenerAdapter {
} else { } else {
MessageEmbed message = EmbedMessageUtils.buildStandar(new EmbedBuilder() MessageEmbed message = EmbedMessageUtils.buildStandar(new EmbedBuilder()
.setTitle(":no_entry_sign: This command is not usable in private message") .setTitle(":no_entry_sign: This command is not usable in private message")
.setColor(Color.red) .setColor(Color.red));
);
event.replyEmbeds(message).setEphemeral(true).queue(); event.replyEmbeds(message).setEphemeral(true).queue();
} }
} else { } else {
if (!commandRunner.isNSFW() || event.getTextChannel().isNSFW()) { if (!commandRunner.isNSFW() || event.getChannel().asTextChannel().isNSFW()) {
commandRunner.action(event); commandRunner.action(event);
} else { } else {
MessageEmbed message = EmbedMessageUtils.buildStandar(new EmbedBuilder() MessageEmbed message = EmbedMessageUtils.buildStandar(new EmbedBuilder()
.setTitle(":underage: This command is only usable in NSFW channels") .setTitle(":underage: This command is only usable in NSFW channels")
.setColor(Color.red) .setColor(Color.red));
);
event.replyEmbeds(message).setEphemeral(true).queue(); event.replyEmbeds(message).setEphemeral(true).queue();
} }
} }
@ -190,19 +183,23 @@ public class BotListener extends ListenerAdapter {
@Override @Override
public void onGuildJoin(GuildJoinEvent event) { public void onGuildJoin(GuildJoinEvent event) {
logger.info("Join new guild! (" + event.getGuild().getName() + " " + event.getGuild().getMembers().size() + " Members)"); logger.info("Join new guild! ({} {} Members)", event.getGuild().getName(),
event.getGuild().getMembers().size());
super.onGuildJoin(event); super.onGuildJoin(event);
getPreference(event.getGuild()); getPreference(event.getGuild());
event.getGuild().loadMembers().onSuccess((members -> logger.debug("[" + event.getGuild().getName() + "] Members loaded"))); event.getGuild().loadMembers()
.onSuccess((members -> logger.debug("[{}] Members loaded", event.getGuild().getName())));
EmbedBuilder eb = new EmbedBuilder().setColor(Color.GREEN) EmbedBuilder eb = new EmbedBuilder().setColor(Color.GREEN)
.setTitle("Hello there !") .setTitle("Hello there !")
.setDescription("Allow me to introduce myself -- I am a CL4P-TP the discord bot, but my friends call me Claptrap ! Or they would, if any of them were real...\n" + .setDescription(
"\nYou can access to my web UI with: " + botConfig.url()) "Allow me to introduce myself -- I am a CL4P-TP the discord bot, but my friends call me Claptrap ! Or they would, if any of them were real...\n"
+
"\nYou can access to my web UI with: " + botConfig.url())
.setImage("https://i.imgur.com/Anf1Srg.gif"); .setImage("https://i.imgur.com/Anf1Srg.gif");
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.buildStandar(eb)).build(); MessageCreateData message = new MessageCreateBuilder().setEmbeds(EmbedMessageUtils.buildStandar(eb)).build();
TextChannel defaultChan = event.getGuild().getDefaultChannel(); TextChannel defaultChan = event.getGuild().getDefaultChannel().asTextChannel();
if (defaultChan != null && defaultChan.canTalk()) { if (defaultChan.canTalk()) {
defaultChan.sendMessage(message).queue(); defaultChan.sendMessage(message).queue();
} else { } else {
for (TextChannel chan : event.getGuild().getTextChannels()) { for (TextChannel chan : event.getGuild().getTextChannels()) {
@ -217,12 +214,10 @@ public class BotListener extends ListenerAdapter {
private GuildPreferenceEntity getPreference(Guild guild) { private GuildPreferenceEntity getPreference(Guild guild) {
Optional<GuildPreferenceEntity> guildPref = guildPreferenceRepository.findByGuildId(guild.getId()); Optional<GuildPreferenceEntity> guildPref = guildPreferenceRepository.findByGuildId(guild.getId());
if (guildPref.isEmpty()) { if (guildPref.isEmpty()) {
logger.info("[" + guild.getName() + "] : Generate default pref"); logger.info("[{}] : Generate default pref", guild.getName());
return guildPreferenceRepository.save(GuildPreferenceEntity.getDefault(guild.getId())); return guildPreferenceRepository.save(GuildPreferenceEntity.getDefault(guild.getId()));
} else{ } else {
return guildPref.get(); return guildPref.get();
} }
} }
} }

View File

@ -1,6 +1,5 @@
package net.Broken; package net.Broken;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
/** /**
@ -43,5 +42,4 @@ public interface Commande {
*/ */
boolean isNSFW(); boolean isNSFW();
} }

View File

@ -1,132 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
public class ChannelsReview implements Commande {
final Logger logger = LogManager.getLogger();
@Override
public void action(String[] args, MessageReceivedEvent event) {
DateFormat format = new SimpleDateFormat("dd.MM.yyyy");
event.getTextChannel().sendMessage("Number of channels found in total : " + event.getGuild().getTextChannels().size()).queue();
if (args.length >= 1) {
try {
SendBackBefore(format.parse(args[0]), event, format);
} catch (ParseException e) {
logger.warn("Can't parse date : " + e.getMessage());
}
} else {
SendBack(event);
}
}
private void SendBackBefore(Date beforeDate, MessageReceivedEvent event, DateFormat format) {
HashMap<String, String> result = new HashMap<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy").withLocale(Locale.ENGLISH);
int charCtl = 0;
for (TextChannel textChannel : event.getGuild().getTextChannels()) {
if (textChannel.hasLatestMessage()) {
String lastMessageId = textChannel.getLatestMessageId();
try {
Message lastMessage = textChannel.retrieveMessageById(lastMessageId).complete();
if (beforeDate.compareTo(format.parse(lastMessage.getTimeCreated().format(formatter))) > 0) {
logger.debug("Last message in channel " + textChannel + " is " + lastMessageId);
String date = lastMessage.getTimeCreated().format(formatter);
charCtl += textChannel.getName().length() + date.length();
result.put(textChannel.getName(), date);
}
} catch (RuntimeException | ParseException e) {
logger.warn("Can't find message with id: " + lastMessageId);
result.put(textChannel.getName(), "ERROR");
charCtl += textChannel.getName().length() + 5;
}
} else {
result.put(textChannel.getName(), "No message or access denied.");
charCtl += textChannel.getName().length() + 30;
}
if (charCtl > 3000) {
event.getTextChannel().sendMessage(EmbedMessageUtils.getLastMessageFromTextChannel(result)).complete();
result = new HashMap<>();
charCtl = 0;
}
}
if (charCtl != 0)
event.getTextChannel().sendMessage(EmbedMessageUtils.getLastMessageFromTextChannel(result)).queue();
}
private void SendBack(MessageReceivedEvent event) {
HashMap<String, String> result = new HashMap<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMMM yyyy").withLocale(Locale.ENGLISH);
int charCtl = 0;
for (TextChannel textChannel : event.getGuild().getTextChannels()) {
if (textChannel.hasLatestMessage()) {
String lastMessageId = textChannel.getLatestMessageId();
logger.debug("Last message in channel " + textChannel + " is " + lastMessageId);
try {
Message lastMessage = textChannel.retrieveMessageById(lastMessageId).complete();
String date = lastMessage.getTimeCreated().format(formatter);
charCtl += textChannel.getName().length() + date.length();
result.put(textChannel.getName(), date);
} catch (RuntimeException e) {
logger.warn("Can't find message with id: " + lastMessageId);
result.put(textChannel.getName(), "ERROR");
charCtl += textChannel.getName().length() + 5;
}
} else {
result.put(textChannel.getName(), "No message or access denied.");
charCtl += textChannel.getName().length() + 30;
}
if (charCtl > 3000) {
event.getTextChannel().sendMessage(EmbedMessageUtils.getLastMessageFromTextChannel(result)).queue();
event.getTextChannel().sendTyping().queue();
result = new HashMap<>();
charCtl = 0;
}
}
if (charCtl != 0)
event.getTextChannel().sendMessage(EmbedMessageUtils.getLastMessageFromTextChannel(result)).queue();
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,39 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
public class Ordre66 implements Commande {
@Override
public void action(String[] args, MessageReceivedEvent event) {
Message rest = event.getTextChannel().sendMessage("Très bien maître " + event.getAuthor().getAsMention() + ". J'arrive ! ").complete();
Message reste = event.getTextChannel().sendMessage("https://media2.giphy.com/media/UfzTayIyH7g5hk2BA2/giphy.gif\n").complete();
}
@Override
public boolean isPrivateUsable() {
return true;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,69 +0,0 @@
package net.Broken.Commands;
import net.Broken.Commande;
import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.Objects;
public class ReportUsers implements Commande {
@Override
public void action(String[] args, MessageReceivedEvent event) {
event.getGuild().loadMembers().onSuccess(members -> {
if (event.getMessage().getMentionedRoles().size() == 1 && args.length == 1) {
RestAction<Void> restAction = null;
for (Member member : members) {
if (member.getRoles().size() == 1) { //check if the member has a role
if (member.getRoles().contains(event.getMessage().getMentionedRoles().get(0))) { //check if the mentioned role is the same as the member's role
restAction = Objects.requireNonNullElseGet(restAction, () -> event.getTextChannel().sendMessage("List des membres : "))
.and(event.getTextChannel().sendMessage(member.getEffectiveName()));
}
}
}
if (restAction != null)
restAction.queue();
} else if (args.length == 0) {
for (Member member : members) {
if (member.getRoles().size() == 0) {
event.getTextChannel().sendMessage(member.getEffectiveName()).complete();
}
}
} else {
event.getTextChannel().sendMessage(EmbedMessageUtils.getReportUsersError()).complete();
}
});
}
@Override
public boolean isPrivateUsable() {
return false;
}
@Override
public boolean isAdminCmd() {
return true;
}
/**
* Determines if the command is usable only by bot level admin user
*
* @return boolean
*/
@Override
public boolean isBotAdminCmd() {
return false;
}
@Override
public boolean isNSFW() {
return false;
}
}

View File

@ -1,6 +1,10 @@
package net.Broken.DB.Entity; package net.Broken.DB.Entity;
import javax.persistence.*; import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity @Entity
public class GuildPreferenceEntity { public class GuildPreferenceEntity {
@ -8,7 +12,7 @@ public class GuildPreferenceEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id; private Integer id;
@Column(unique=true) @Column(unique = true)
private String guildId; private String guildId;
private boolean welcome; private boolean welcome;
@ -27,17 +31,16 @@ public class GuildPreferenceEntity {
private String autoVoiceChannelID; private String autoVoiceChannelID;
private String autoVoiceChannelTitle; private String autoVoiceChannelTitle;
public GuildPreferenceEntity(String guildId, public GuildPreferenceEntity(String guildId,
boolean welcome, boolean welcome,
String welcomeMessage, String welcomeMessage,
String welcomeChanelID, String welcomeChanelID,
boolean defaultRole, boolean defaultRole,
String defaultRoleId, String defaultRoleId,
boolean dailyMadame, boolean dailyMadame,
boolean autoVoice, boolean autoVoice,
String autoVoiceChannelID, String autoVoiceChannelID,
String autoVoiceChannelTitle) { String autoVoiceChannelTitle) {
this.guildId = guildId; this.guildId = guildId;
this.welcome = welcome; this.welcome = welcome;
this.welcomeMessage = welcomeMessage; this.welcomeMessage = welcomeMessage;
@ -53,9 +56,9 @@ public class GuildPreferenceEntity {
public GuildPreferenceEntity() { public GuildPreferenceEntity() {
} }
public static GuildPreferenceEntity getDefault(String guildId) { public static GuildPreferenceEntity getDefault(String guildId) {
return new GuildPreferenceEntity(guildId, false, "Welcome to this awesome server @name! ", null, false, null, true, false, null, null); return new GuildPreferenceEntity(guildId, false, "Welcome to this awesome server @name! ", null, false, null,
true, false, null, null);
} }
public Integer getId() { public Integer getId() {

View File

@ -1,12 +1,19 @@
package net.Broken.DB.Entity; package net.Broken.DB.Entity;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import net.Broken.Api.Security.Data.DiscordOauthUserInfo; import net.Broken.Api.Security.Data.DiscordOauthUserInfo;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import javax.persistence.*;
import java.util.List;
/** /**
* Entity for DB. Represent confirmed user account. * Entity for DB. Represent confirmed user account.
*/ */
@ -51,7 +58,6 @@ public class UserEntity {
this.avatar = discordOauthUserInfo.avatar(); this.avatar = discordOauthUserInfo.avatar();
} }
public Integer getId() { public Integer getId() {
return id; return id;
} }

View File

@ -2,7 +2,12 @@ package net.Broken.DB.Entity;
import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnDefault;
import javax.persistence.*; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
@Entity @Entity
public class UserStats { public class UserStats {
@ -11,7 +16,6 @@ public class UserStats {
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
private String guildId; private String guildId;
@ManyToOne @ManyToOne

View File

@ -1,9 +1,10 @@
package net.Broken.DB.Repository; package net.Broken.DB.Repository;
import net.Broken.DB.Entity.GuildPreferenceEntity; import java.util.Optional;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import java.util.Optional; import net.Broken.DB.Entity.GuildPreferenceEntity;
public interface GuildPreferenceRepository extends CrudRepository<GuildPreferenceEntity, Integer> { public interface GuildPreferenceRepository extends CrudRepository<GuildPreferenceEntity, Integer> {
Optional<GuildPreferenceEntity> findByGuildId(String id); Optional<GuildPreferenceEntity> findByGuildId(String id);

View File

@ -1,13 +1,10 @@
package net.Broken; package net.Broken;
import net.Broken.DB.Entity.GuildPreferenceEntity; import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository; import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.DB.Repository.UserRepository;
import net.Broken.Tools.Command.SlashCommandLoader; import net.Broken.Tools.Command.SlashCommandLoader;
import net.Broken.Tools.DayListener.DayListener; import net.Broken.Tools.DayListener.DayListener;
import net.Broken.Tools.DayListener.Listeners.DailyMadame; import net.Broken.Tools.DayListener.Listeners.DailyMadame;
import net.Broken.Tools.UserManager.Stats.UserStatsUtils;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.OnlineStatus; import net.dv8tion.jda.api.OnlineStatus;
@ -19,14 +16,12 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import javax.security.auth.login.LoginException;
import java.util.List;
public class Init { public class Init {
static private final Logger logger = LogManager.getLogger(); static private final Logger logger = LogManager.getLogger();
private Init() {
}
static JDA initJda(BotConfigLoader config) { static JDA initJda(BotConfigLoader config) {
logger.info("-----------------------INIT-----------------------"); logger.info("-----------------------INIT-----------------------");
if (config == null) { if (config == null) {
@ -47,20 +42,18 @@ public class Init {
.setAutoReconnect(true); .setAutoReconnect(true);
jda.getPresence().setPresence(OnlineStatus.DO_NOT_DISTURB, Activity.playing("Loading...")); jda.getPresence().setPresence(OnlineStatus.DO_NOT_DISTURB, Activity.playing("Loading..."));
logger.info("Connected on " + jda.getGuilds().size() + " Guilds:"); logger.info("Connected on {} Guilds:", jda.getGuilds().size());
for (Guild server : jda.getGuilds()) { for (Guild server : jda.getGuilds()) {
server.loadMembers().get(); server.loadMembers();
logger.info("... " + server.getName() + " " + server.getMembers().size() + " Members");
} }
return jda; return jda;
} catch (LoginException | InterruptedException e) { } catch (InterruptedException e) {
logger.catching(e); logger.catching(e);
return null; return null;
} }
} }
} }
static void polish(JDA jda, BotConfigLoader config) { static void polish(JDA jda, BotConfigLoader config) {
logger.info("Check database..."); logger.info("Check database...");
checkDatabase(); checkDatabase();
@ -76,54 +69,43 @@ public class Init {
logger.info("-----------------------END INIT-----------------------"); logger.info("-----------------------END INIT-----------------------");
} }
private static void checkDatabase() { private static void checkDatabase() {
ApplicationContext context = SpringContext.getAppContext(); ApplicationContext context = SpringContext.getAppContext();
UserRepository userRepository = (UserRepository) context.getBean("userRepository");
List<UserEntity> users = (List<UserEntity>) userRepository.findAll();
UserStatsUtils userStatsUtils = UserStatsUtils.getINSTANCE();
logger.debug("Stats..."); logger.debug("Stats...");
// for (UserEntity userEntity : users) {
// logger.debug("..." + userEntity.getName());
// userStatsUtils.getUserStats(userEntity);
//
// }
logger.debug("Guild Prefs..."); logger.debug("Guild Prefs...");
GuildPreferenceRepository guildPreference = context.getBean(GuildPreferenceRepository.class); GuildPreferenceRepository guildPreference = context.getBean(GuildPreferenceRepository.class);
for(GuildPreferenceEntity pref :guildPreference.findAll()){ for (GuildPreferenceEntity pref : guildPreference.findAll()) {
boolean save = false; boolean save = false;
if(pref.getWelcomeMessage() != null && pref.getWelcomeMessage().equals(" ")){ if (pref.getWelcomeMessage() != null && pref.getWelcomeMessage().equals(" ")) {
pref.setWelcomeMessage(null); pref.setWelcomeMessage(null);
save = true; save = true;
} }
if(pref.getWelcomeChanelID() != null && pref.getWelcomeChanelID().equals(" ")){ if (pref.getWelcomeChanelID() != null && pref.getWelcomeChanelID().equals(" ")) {
pref.setWelcomeChanelID(null); pref.setWelcomeChanelID(null);
save = true; save = true;
} }
if(pref.getWelcomeChanelID() != null && pref.getWelcomeChanelID().equals(" ")){ if (pref.getWelcomeChanelID() != null && pref.getWelcomeChanelID().equals(" ")) {
pref.setWelcomeChanelID(null); pref.setWelcomeChanelID(null);
save = true; save = true;
} }
if(pref.getDefaultRoleId() != null && pref.getDefaultRoleId().equals(" ")){ if (pref.getDefaultRoleId() != null && pref.getDefaultRoleId().equals(" ")) {
pref.setDefaultRoleId(null); pref.setDefaultRoleId(null);
save = true; save = true;
} }
if(pref.getAutoVoiceChannelID() != null && pref.getAutoVoiceChannelID().equals(" ")){ if (pref.getAutoVoiceChannelID() != null && pref.getAutoVoiceChannelID().equals(" ")) {
pref.setAutoVoiceChannelID(null); pref.setAutoVoiceChannelID(null);
save = true; save = true;
} }
if(pref.getAutoVoiceChannelTitle() != null && pref.getAutoVoiceChannelTitle().equals(" ")){ if (pref.getAutoVoiceChannelTitle() != null && pref.getAutoVoiceChannelTitle().equals(" ")) {
pref.setAutoVoiceChannelTitle(null); pref.setAutoVoiceChannelTitle(null);
save = true; save = true;
} }
if(save){ if (save) {
guildPreference.save(pref); guildPreference.save(pref);
} }
} }
} }
} }

View File

@ -1,6 +1,7 @@
package net.Broken; package net.Broken;
import net.dv8tion.jda.api.JDA; import java.util.HashMap;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
@ -11,7 +12,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import java.util.HashMap; import net.dv8tion.jda.api.JDA;
/** /**
* Main Class * Main Class
@ -28,7 +29,6 @@ public class MainBot {
public static int messageTimeOut = 10; public static int messageTimeOut = 10;
public static int gifMessageTimeOut = 30; public static int gifMessageTimeOut = 30;
private static final Logger logger = LogManager.getLogger(); private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) { public static void main(String[] args) {
@ -56,8 +56,7 @@ public class MainBot {
@Bean @Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() { public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer propsConfig PropertySourcesPlaceholderConfigurer propsConfig = new PropertySourcesPlaceholderConfigurer();
= new PropertySourcesPlaceholderConfigurer();
propsConfig.setLocation(new ClassPathResource("git.properties")); propsConfig.setLocation(new ClassPathResource("git.properties"));
propsConfig.setIgnoreResourceNotFound(true); propsConfig.setIgnoreResourceNotFound(true);
propsConfig.setIgnoreUnresolvablePlaceholders(true); propsConfig.setIgnoreUnresolvablePlaceholders(true);

View File

@ -1,6 +1,7 @@
package net.Broken; package net.Broken;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
@ -10,7 +11,7 @@ import java.util.List;
* Interface that define command structure. * Interface that define command structure.
*/ */
public interface SlashCommand { public interface SlashCommand {
void action(SlashCommandEvent event); void action(SlashCommandInteractionEvent event);
String getDescription(); String getDescription();
@ -34,7 +35,5 @@ public interface SlashCommand {
boolean isPrivateUsable(); boolean isPrivateUsable();
DefaultMemberPermissions getDefaultPermissions();
boolean isDisableByDefault();
} }

View File

@ -1,11 +1,11 @@
package net.Broken.SlashCommands; package net.Broken.SlashCommands;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -17,10 +17,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import net.Broken.SlashCommand; import net.Broken.SlashCommand;
import net.Broken.Tools.EmbedMessageUtils; import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
/** /**
* Command that return a random picture of cat. * Command that return a random picture of cat.
@ -29,32 +31,34 @@ public class Cat implements SlashCommand {
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
@Override @Override
public void action(SlashCommandEvent event) { public void action(SlashCommandInteractionEvent event) {
try { try {
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://aws.random.cat/meow")) .uri(URI.create("https://aws.random.cat/meow"))
.GET() .GET()
.build(); .build();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) { if (response.statusCode() != 200) {
logger.warn("[CAT] Fail to fetch cat: Status Code: " + response.statusCode() + " Body:" + response.body()); logger.warn("[CAT] Fail to fetch cat: Status Code: {} Body: {}", response.statusCode(),
response.body());
throw new IOException(); throw new IOException();
} }
TypeReference<HashMap<String, String>> typeRef = new TypeReference<>() {}; TypeReference<HashMap<String, String>> typeRef = new TypeReference<>() {
};
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
HashMap<String, String> json = mapper.readValue(response.body(), typeRef); HashMap<String, String> json = mapper.readValue(response.body(), typeRef);
event.reply(json.get("file")).queue(); event.reply(json.get("file")).queue();
} catch (InterruptedException | IOException e) { } catch (InterruptedException | IOException e) {
logger.catching(e); logger.catching(e);
event.reply(new MessageBuilder().setEmbeds(EmbedMessageUtils.getInternalError()).build()).setEphemeral(true).queue(); event.reply(new MessageCreateBuilder().setEmbeds(EmbedMessageUtils.getInternalError()).build())
.setEphemeral(true)
.queue();
} }
} }
@Override @Override
@ -64,15 +68,14 @@ public class Cat implements SlashCommand {
@Override @Override
public List<OptionData> getOptions() { public List<OptionData> getOptions() {
return null; return Collections.emptyList();
} }
@Override @Override
public List<SubcommandData> getSubcommands() { public List<SubcommandData> getSubcommands() {
return null; return Collections.emptyList();
} }
/** /**
* Determines if the command is usable only by bot level admin user * Determines if the command is usable only by bot level admin user
* *
@ -94,7 +97,8 @@ public class Cat implements SlashCommand {
} }
@Override @Override
public boolean isDisableByDefault() { public DefaultMemberPermissions getDefaultPermissions() {
return false; return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND);
} }
} }

View File

@ -1,29 +1,33 @@
package net.Broken.SlashCommands; package net.Broken.SlashCommands;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.Broken.SlashCommand; import net.Broken.SlashCommand;
import net.Broken.Tools.EmbedMessageUtils; import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import java.util.ArrayList; import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import java.util.List;
public class Clear implements SlashCommand { public class Clear implements SlashCommand {
@Override @Override
public void action(SlashCommandEvent event) { public void action(SlashCommandInteractionEvent event) {
if (event.getMember().hasPermission(Permission.MESSAGE_MANAGE)) { if (event.getMember().hasPermission(Permission.MESSAGE_MANAGE)) {
event.reply(":white_check_mark: Done").setEphemeral(true).queue(); event.reply(":white_check_mark: Done").setEphemeral(true).queue();
long n = event.getOption("n").getAsLong(); long n = event.getOption("n").getAsLong();
MessageChannel chanel = event.getChannel(); MessageChannel chanel = event.getChannel();
chanel.getIterableHistory().takeAsync((int) n).thenAccept(chanel::purgeMessages); chanel.getIterableHistory().takeAsync((int) n).thenAccept(chanel::purgeMessages);
} else { } else {
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getFlushError("You are not a supreme being, you cannot do that !")).build(); MessageCreateData message = new MessageCreateBuilder()
.setEmbeds(EmbedMessageUtils.getFlushError("You are not a supreme being, you cannot do that !"))
.build();
event.reply(message).setEphemeral(true).queue(); event.reply(message).setEphemeral(true).queue();
} }
} }
@ -42,7 +46,7 @@ public class Clear implements SlashCommand {
@Override @Override
public List<SubcommandData> getSubcommands() { public List<SubcommandData> getSubcommands() {
return null; return Collections.emptyList();
} }
@Override @Override
@ -61,7 +65,8 @@ public class Clear implements SlashCommand {
} }
@Override @Override
public boolean isDisableByDefault() { public DefaultMemberPermissions getDefaultPermissions() {
return true; return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_MANAGE);
} }
} }

View File

@ -1,48 +1,52 @@
package net.Broken.SlashCommands; package net.Broken.SlashCommands;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.Broken.Audio.GuildAudioBotService;
import net.Broken.SlashCommand; import net.Broken.SlashCommand;
import net.Broken.Audio.GuildAudioBotService;
import net.Broken.Tools.EmbedMessageUtils; import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.entities.VoiceChannel; import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
import org.apache.logging.log4j.LogManager; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import org.apache.logging.log4j.Logger; import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import java.util.ArrayList;
import java.util.List;
/** /**
* Command that return a random picture of cat. * Command that return a random picture of cat.
*/ */
public class Music implements SlashCommand { public class Music implements SlashCommand {
private static final String PLAYLIST_LIMIT = "playlist-limit";
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
@Override @Override
public void action(SlashCommandEvent event) { public void action(SlashCommandInteractionEvent event) {
GuildAudioBotService audio = GuildAudioBotService.getInstance(event.getGuild()); GuildAudioBotService audio = GuildAudioBotService.getInstance(event.getGuild());
String action = event.getSubcommandName(); String action = event.getSubcommandName();
event.deferReply().queue(); event.deferReply().queue();
switch (action) { switch (action) {
case "play": case "play":
if (event.getMember().getVoiceState().inVoiceChannel()) { if (event.getMember().getVoiceState().inAudioChannel()) {
VoiceChannel voiceChanel = event.getMember().getVoiceState().getChannel(); AudioChannelUnion voiceChanel = event.getMember().getVoiceState().getChannel();
logger.info("Connecting to " + voiceChanel.getName() + "..."); logger.info("Connecting to {}...", voiceChanel.getName());
OptionMapping url = event.getOption("url"); OptionMapping url = event.getOption("url");
if (event.getOption("playlist-limit") == null) { if (event.getOption(PLAYLIST_LIMIT) == null) {
audio.loadAndPlay(event, voiceChanel, url.getAsString(), 30, false); audio.loadAndPlay(event, voiceChanel, url.getAsString(), 30, false);
} else { } else {
long limit = event.getOption("playlist-limit").getAsLong(); long limit = event.getOption(PLAYLIST_LIMIT).getAsLong();
audio.loadAndPlay(event, voiceChanel, url.getAsString(), (int) limit, false); audio.loadAndPlay(event, voiceChanel, url.getAsString(), (int) limit, false);
} }
} else { } else {
Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("You are not in a voice channel !")).build(); MessageCreateData message = new MessageCreateBuilder()
.setEmbeds(EmbedMessageUtils.getMusicError("You are not in a voice channel !")).build();
event.getHook().setEphemeral(true).sendMessage(message).queue(); event.getHook().setEphemeral(true).sendMessage(message).queue();
} }
break; break;
@ -52,34 +56,34 @@ public class Music implements SlashCommand {
if (event.getOption("next") != null) { if (event.getOption("next") != null) {
next = event.getOption("next").getAsBoolean(); next = event.getOption("next").getAsBoolean();
} }
if (event.getOption("playlist-limit") == null) { if (event.getOption(PLAYLIST_LIMIT) == null) {
audio.add(event, url.getAsString(), 30, next); audio.add(event, url.getAsString(), 30, next);
} else { } else {
long limit = event.getOption("playlist-limit").getAsLong(); long limit = event.getOption(PLAYLIST_LIMIT).getAsLong();
audio.add(event, url.getAsString(), (int) limit, next); audio.add(event, url.getAsString(), (int) limit, next);
} }
break; break;
case "pause": case "pause":
audio.pause(event); audio.pause(event.getHook());
break; break;
case "resume": case "resume":
audio.resume(event); audio.resume(event.getHook());
break; break;
case "next": case "next":
audio.skipTrack(event); audio.skipTrack(event.getHook());
break; break;
case "stop": case "stop":
case "disconnect": case "disconnect":
audio.stop(event); audio.stop(event.getHook());
break; break;
case "info": case "info":
audio.info(event); audio.info(event.getHook());
break; break;
case "flush": case "flush":
audio.flush(event); audio.flush(event.getHook());
break; break;
case "list": case "list":
audio.list(event); audio.list(event.getHook());
break; break;
} }
} }
@ -91,7 +95,7 @@ public class Music implements SlashCommand {
@Override @Override
public List<OptionData> getOptions() { public List<OptionData> getOptions() {
return null; return Collections.emptyList();
} }
@Override @Override
@ -99,11 +103,14 @@ public class Music implements SlashCommand {
ArrayList<SubcommandData> subCommandList = new ArrayList<>(); ArrayList<SubcommandData> subCommandList = new ArrayList<>();
subCommandList.add(new SubcommandData("play", "Play music") subCommandList.add(new SubcommandData("play", "Play music")
.addOption(OptionType.STRING, "url", "The URL of the video to play", true) .addOption(OptionType.STRING, "url", "The URL of the video to play", true)
.addOption(OptionType.INTEGER, "playlist-limit", "If a playlist is loaded, enter the max number of loaded tracks (default to 30)")); .addOption(OptionType.INTEGER, PLAYLIST_LIMIT,
"If a playlist is loaded, enter the max number of loaded tracks (default to 30)"));
subCommandList.add(new SubcommandData("add", "Add track to queue") subCommandList.add(new SubcommandData("add", "Add track to queue")
.addOption(OptionType.STRING, "url", " The URL of the video to play", true) .addOption(OptionType.STRING, "url", " The URL of the video to play", true)
.addOption(OptionType.BOOLEAN, "next", "If true, track will be added on top of the playlist and will be the next to play") .addOption(OptionType.BOOLEAN, "next",
.addOption(OptionType.INTEGER, "playlist-limit", "If a playlist is loaded, enter the max number of loaded tracks (default to 30)")); "If true, track will be added on top of the playlist and will be the next to play")
.addOption(OptionType.INTEGER, PLAYLIST_LIMIT,
"If a playlist is loaded, enter the max number of loaded tracks (default to 30)"));
subCommandList.add(new SubcommandData("pause", "Pause playback")); subCommandList.add(new SubcommandData("pause", "Pause playback"));
subCommandList.add(new SubcommandData("resume", "Resume playback")); subCommandList.add(new SubcommandData("resume", "Resume playback"));
subCommandList.add(new SubcommandData("stop", "Stop playback")); subCommandList.add(new SubcommandData("stop", "Stop playback"));
@ -114,7 +121,6 @@ public class Music implements SlashCommand {
return subCommandList; return subCommandList;
} }
/** /**
* Determines if the command is usable only by bot level admin user * Determines if the command is usable only by bot level admin user
* *
@ -136,7 +142,8 @@ public class Music implements SlashCommand {
} }
@Override @Override
public boolean isDisableByDefault() { public DefaultMemberPermissions getDefaultPermissions() {
return false; return DefaultMemberPermissions.ENABLED;
} }
} }

View File

@ -1,9 +1,12 @@
package net.Broken.SlashCommands.Over18; package net.Broken.SlashCommands.Over18;
import org.apache.logging.log4j.LogManager;
import net.Broken.Tools.Command.Ignore; import net.Broken.Tools.Command.Ignore;
import net.Broken.Tools.Command.NoDev; import net.Broken.Tools.Command.NoDev;
import net.Broken.Tools.Command.NumberedSlashCommand; import net.Broken.Tools.Command.NumberedSlashCommand;
import org.apache.logging.log4j.LogManager; import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
@NoDev @NoDev
@Ignore @Ignore
@ -13,7 +16,6 @@ public class Ass extends NumberedSlashCommand {
super(LogManager.getLogger(), "http://les400culs.com/", "-2/", "featured-img", "img"); super(LogManager.getLogger(), "http://les400culs.com/", "-2/", "featured-img", "img");
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Return random image from les400culs.com"; return "Return random image from les400culs.com";
@ -35,7 +37,7 @@ public class Ass extends NumberedSlashCommand {
} }
@Override @Override
public boolean isDisableByDefault() { public DefaultMemberPermissions getDefaultPermissions() {
return true; return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND);
} }
} }

View File

@ -3,6 +3,9 @@ package net.Broken.SlashCommands.Over18;
import net.Broken.Tools.Command.Ignore; import net.Broken.Tools.Command.Ignore;
import net.Broken.Tools.Command.NoDev; import net.Broken.Tools.Command.NoDev;
import net.Broken.Tools.Command.NumberedSlashCommand; import net.Broken.Tools.Command.NumberedSlashCommand;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -15,7 +18,6 @@ public class Boobs extends NumberedSlashCommand {
super(LogManager.getLogger(), "http://lesaintdesseins.fr/", "-2/", "featured-img", "img"); super(LogManager.getLogger(), "http://lesaintdesseins.fr/", "-2/", "featured-img", "img");
} }
@Override @Override
public String getDescription() { public String getDescription() {
return "Return random image from les400culs.com"; return "Return random image from les400culs.com";
@ -37,7 +39,7 @@ public class Boobs extends NumberedSlashCommand {
} }
@Override @Override
public boolean isDisableByDefault() { public DefaultMemberPermissions getDefaultPermissions() {
return true; return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND);
} }
} }

View File

@ -2,6 +2,8 @@ package net.Broken.SlashCommands.Over18;
import net.Broken.Tools.Command.NoDev; import net.Broken.Tools.Command.NoDev;
import net.Broken.Tools.Command.NumberedSlashCommand; import net.Broken.Tools.Command.NumberedSlashCommand;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.Broken.Tools.FindContentOnWebPage; import net.Broken.Tools.FindContentOnWebPage;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -15,6 +17,7 @@ public class Madame extends NumberedSlashCommand {
public Madame() { public Madame() {
super(LogManager.getLogger(), "https://www.bonjourmadame.fr/page/", "/"); super(LogManager.getLogger(), "https://www.bonjourmadame.fr/page/", "/");
} }
/** /**
* Detect if picture link go to Tepeee * Detect if picture link go to Tepeee
* *
@ -23,7 +26,8 @@ public class Madame extends NumberedSlashCommand {
* @throws StringIndexOutOfBoundsException * @throws StringIndexOutOfBoundsException
* @throws IOException * @throws IOException
*/ */
private boolean scanPageForTipeee(String url, Logger logger) throws StringIndexOutOfBoundsException, IOException, InterruptedException { private boolean scanPageForTipeee(String url, Logger logger)
throws StringIndexOutOfBoundsException, IOException, InterruptedException {
String content = FindContentOnWebPage.getSourceUrl(url); String content = FindContentOnWebPage.getSourceUrl(url);
String imgClickLink = content.substring(content.indexOf("class=\"post-content")); String imgClickLink = content.substring(content.indexOf("class=\"post-content"));
imgClickLink = imgClickLink.substring(imgClickLink.indexOf("<a")); imgClickLink = imgClickLink.substring(imgClickLink.indexOf("<a"));
@ -46,7 +50,6 @@ public class Madame extends NumberedSlashCommand {
return url; return url;
} }
@Override @Override
public String poll() throws IOException, InterruptedException { public String poll() throws IOException, InterruptedException {
boolean success = false; boolean success = false;
@ -57,11 +60,10 @@ public class Madame extends NumberedSlashCommand {
int randomResult = randomQueue.poll(); int randomResult = randomQueue.poll();
String url = baseURL + randomResult + urlSuffix; String url = baseURL + randomResult + urlSuffix;
logger.debug("URL: " + url); logger.debug("URL: {}", url);
if (scanPageForTipeee(url, logger)) { if (scanPageForTipeee(url, logger)) {
logger.debug("Advertisement detected! Retry! (" + url + ")"); logger.debug("Advertisement detected! Retry! ({})", url);
} else { } else {
imgUrl = FindContentOnWebPage.doYourJob(url, "post-content", "img"); imgUrl = FindContentOnWebPage.doYourJob(url, "post-content", "img");
@ -94,7 +96,7 @@ public class Madame extends NumberedSlashCommand {
} }
@Override @Override
public boolean isDisableByDefault() { public DefaultMemberPermissions getDefaultPermissions() {
return true; return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND);
} }
} }

View File

@ -1,27 +1,28 @@
package net.Broken.SlashCommands; package net.Broken.SlashCommands;
import java.util.Collections;
import java.util.List;
import net.Broken.BotConfigLoader; import net.Broken.BotConfigLoader;
import net.Broken.SlashCommand; import net.Broken.SlashCommand;
import net.Broken.SpringContext; import net.Broken.SpringContext;
import net.Broken.Tools.UserManager.Stats.UserStatsUtils; import net.Broken.Tools.UserManager.Stats.UserStatsUtils;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
import net.dv8tion.jda.api.interactions.components.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import java.util.List;
public class Rank implements SlashCommand { public class Rank implements SlashCommand {
@Override @Override
public void action(SlashCommandEvent event) { public void action(SlashCommandInteractionEvent event) {
String url = SpringContext.getAppContext().getBean(BotConfigLoader.class).url(); String url = SpringContext.getAppContext().getBean(BotConfigLoader.class).url();
event.deferReply().queue(); event.deferReply().queue();
UserStatsUtils userStats = UserStatsUtils.getINSTANCE(); UserStatsUtils userStats = UserStatsUtils.getINSTANCE();
MessageEmbed messageEmbed = userStats.getRankMessage(event.getMember()); MessageEmbed messageEmbed = userStats.getRankMessage(event.getMember());
event.getHook().sendMessageEmbeds(messageEmbed).addActionRow( event.getHook().sendMessageEmbeds(messageEmbed).addActionRow(
Button.link("https://" + url + "/rank", "More stats") Button.link("https://" + url + "/rank", "More stats")).queue();
).queue();
} }
@Override @Override
@ -31,12 +32,12 @@ public class Rank implements SlashCommand {
@Override @Override
public List<OptionData> getOptions() { public List<OptionData> getOptions() {
return null; return Collections.emptyList();
} }
@Override @Override
public List<SubcommandData> getSubcommands() { public List<SubcommandData> getSubcommands() {
return null; return Collections.emptyList();
} }
@Override @Override
@ -55,7 +56,7 @@ public class Rank implements SlashCommand {
} }
@Override @Override
public boolean isDisableByDefault() { public DefaultMemberPermissions getDefaultPermissions() {
return false; return DefaultMemberPermissions.ENABLED;
} }
} }

View File

@ -1,20 +1,20 @@
package net.Broken.Tools; package net.Broken.Tools;
import static net.Broken.MainBot.jda;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.VoiceChannel;
import net.dv8tion.jda.api.requests.RestAction;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static net.Broken.MainBot.jda; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel;
import net.dv8tion.jda.api.requests.RestAction;
public class AutoVoiceChannel { public class AutoVoiceChannel {
private static final HashMap<String, AutoVoiceChannel> INSTANCE_MAP = new HashMap<>(); private static final HashMap<String, AutoVoiceChannel> INSTANCE_MAP = new HashMap<>();
@ -34,29 +34,30 @@ public class AutoVoiceChannel {
return INSTANCE_MAP.get(guild.getId()); return INSTANCE_MAP.get(guild.getId());
} }
public void join(VoiceChannel voiceChannel) { public void join(AudioChannel voiceChannel) {
Guild guild = jda.getGuildById(guildID); Guild guild = jda.getGuildById(guildID);
if (guild == null) if (guild == null)
return; return;
GuildPreferenceEntity pref = SettingsUtils.getInstance().getPreference(guild); GuildPreferenceEntity pref = SettingsUtils.getInstance().getPreference(guild);
if (pref.isAutoVoice() && voiceChannel.getId().equals(pref.getAutoVoiceChannelID())) { if (pref.isAutoVoice() && voiceChannel.getId().equals(pref.getAutoVoiceChannelID())) {
logger.info("Creating new voice channel for Guild : " + guild.getName()); logger.info("Creating new voice channel for Guild : {}", guild.getName());
VoiceChannel newChannel = voiceChannel.createCopy().complete();
int next = getNextNumber(); int next = getNextNumber();
String title = pref.getAutoVoiceChannelTitle(); String title = pref.getAutoVoiceChannelTitle();
if (title.isEmpty()) { if (title.isEmpty()) {
title = "Voice @count"; title = "Voice @count";
} }
title = title.replace("@count", Integer.toString(next)); title = title.replace("@count", Integer.toString(next));
newChannel.getManager().setName(title).setPosition(voiceChannel.getPosition()).queue(); voiceChannel.createCopy().setName(title).queue(newChannel -> {
voiceChannel.getGuild().modifyVoiceChannelPositions().selectPosition(newChannel)
createdChannels.put(next, newChannel.getId()); .moveBelow(voiceChannel).queue();
moveMembers(voiceChannel.getMembers(), newChannel); moveMembers(voiceChannel.getMembers(), (AudioChannel) newChannel);
createdChannels.put(next, newChannel.getId());
});
} }
} }
public void leave(VoiceChannel voiceChannel) { public void leave(AudioChannel voiceChannel) {
if (voiceChannel.getMembers().isEmpty()) { if (voiceChannel.getMembers().isEmpty()) {
String id = voiceChannel.getId(); String id = voiceChannel.getId();
for (Map.Entry<Integer, String> entry : createdChannels.entrySet()) { for (Map.Entry<Integer, String> entry : createdChannels.entrySet()) {
@ -79,7 +80,7 @@ public class AutoVoiceChannel {
return 999; return 999;
} }
private void moveMembers(List<Member> members, VoiceChannel destination) { private void moveMembers(List<Member> members, AudioChannel destination) {
logger.debug("Moving Members to new voice channel..."); logger.debug("Moving Members to new voice channel...");
RestAction<Void> restAction = null; RestAction<Void> restAction = null;
for (Member member : members) { for (Member member : members) {

View File

@ -1,12 +1,13 @@
package net.Broken.Tools.Command; package net.Broken.Tools.Command;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
/** /**
* *
*/ */
@ -38,8 +39,7 @@ public class CommandParser {
for (int i = 0; i < args.length; i++) for (int i = 0; i < args.length; i++)
args[i] = args[i].replace('$', ' '); args[i] = args[i].replace('$', ' ');
logger.info("Author: {}, Command: {}, args: {}", e.getAuthor().getName(), commande, Arrays.toString(args));
logger.info("Author: " + e.getAuthor().getName() + ", Command: " + commande + ", args: " + Arrays.toString(args));
return new CommandContainer(brt, sansTete, splitSansTete, commande, args, e); return new CommandContainer(brt, sansTete, splitSansTete, commande, args, e);
@ -56,7 +56,8 @@ public class CommandParser {
public final String[] args; public final String[] args;
public final MessageReceivedEvent event; public final MessageReceivedEvent event;
public CommandContainer(String brut, String sansTete, String[] splitSansTete, String commande, String[] args, MessageReceivedEvent e) { public CommandContainer(String brut, String sansTete, String[] splitSansTete, String commande, String[] args,
MessageReceivedEvent e) {
this.brut = brut; this.brut = brut;
this.sansTete = sansTete; this.sansTete = sansTete;
this.splitSansTete = splitSansTete; this.splitSansTete = splitSansTete;

View File

@ -1,6 +1,7 @@
package net.Broken.Tools.Command; package net.Broken.Tools.Command;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@ -13,12 +14,13 @@ import net.Broken.Tools.FindContentOnWebPage;
import net.Broken.Tools.LimitChecker; import net.Broken.Tools.LimitChecker;
import net.Broken.Tools.Random.TrueRandom; import net.Broken.Tools.Random.TrueRandom;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
/** /**
* Abstact class used for all command that need to find the max number of page on a web site. * Abstact class used for all command that need to find the max number of page
* on a web site.
*/ */
@Ignore @Ignore
public abstract class NumberedSlashCommand implements SlashCommand { public abstract class NumberedSlashCommand implements SlashCommand {
@ -39,7 +41,7 @@ public abstract class NumberedSlashCommand implements SlashCommand {
* @param divClass DivClass to search to extract image * @param divClass DivClass to search to extract image
* @param htmlType HTML tag to extract image (img) * @param htmlType HTML tag to extract image (img)
*/ */
public NumberedSlashCommand(Logger logger, String baseURL, String urlSuffix, String divClass, String htmlType) { protected NumberedSlashCommand(Logger logger, String baseURL, String urlSuffix, String divClass, String htmlType) {
this.logger = logger; this.logger = logger;
this.baseURL = baseURL; this.baseURL = baseURL;
this.divClass = divClass; this.divClass = divClass;
@ -48,19 +50,19 @@ public abstract class NumberedSlashCommand implements SlashCommand {
try { try {
logger.debug("Checking max..."); logger.debug("Checking max...");
maxNumber = LimitChecker.doYourJob(baseURL, 2, urlSuffix); maxNumber = LimitChecker.doYourJob(baseURL, 2, urlSuffix);
logger.info("Limit is " + maxNumber); logger.info("Limit is {}", maxNumber);
} catch (IOException e) { } catch (IOException e) {
logger.catching(e); logger.catching(e);
} }
} }
public NumberedSlashCommand(Logger logger, String baseURL, String urlSuffix) { protected NumberedSlashCommand(Logger logger, String baseURL, String urlSuffix) {
this(logger, baseURL, urlSuffix, null, null); this(logger, baseURL, urlSuffix, null, null);
} }
@Override @Override
public void action(SlashCommandEvent event) { public void action(SlashCommandInteractionEvent event) {
event.deferReply().queue(); event.deferReply().queue();
try { try {
String result = poll(); String result = poll();
@ -72,7 +74,6 @@ public abstract class NumberedSlashCommand implements SlashCommand {
} }
} }
private void fillRandomQueue() throws IOException { private void fillRandomQueue() throws IOException {
TrueRandom trueRandom = TrueRandom.getINSTANCE(); TrueRandom trueRandom = TrueRandom.getINSTANCE();
List<Integer> numbers = trueRandom.getNumbers(minNumber, maxNumber); List<Integer> numbers = trueRandom.getNumbers(minNumber, maxNumber);
@ -82,7 +83,7 @@ public abstract class NumberedSlashCommand implements SlashCommand {
} }
protected void checkRandom() throws IOException { protected void checkRandom() throws IOException {
logger.trace("Queue size: " + randomQueue.size()); logger.trace("Queue size: {}", randomQueue.size());
if (randomQueue.isEmpty()) { if (randomQueue.isEmpty()) {
logger.debug("Queue empty, update it."); logger.debug("Queue empty, update it.");
fillRandomQueue(); fillRandomQueue();
@ -97,12 +98,12 @@ public abstract class NumberedSlashCommand implements SlashCommand {
@Override @Override
public List<OptionData> getOptions() { public List<OptionData> getOptions() {
return null; return Collections.emptyList();
} }
@Override @Override
public List<SubcommandData> getSubcommands() { public List<SubcommandData> getSubcommands() {
return null; return Collections.emptyList();
} }
} }

View File

@ -1,19 +1,20 @@
package net.Broken.Tools.Command; package net.Broken.Tools.Command;
import net.Broken.BotConfigLoader; import java.lang.reflect.InvocationTargetException;
import net.Broken.MainBot; import java.util.Set;
import net.Broken.SlashCommand;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.reflections.Reflections; import org.reflections.Reflections;
import org.reflections.util.ClasspathHelper; import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder; import org.reflections.util.ConfigurationBuilder;
import java.lang.reflect.InvocationTargetException; import net.Broken.BotConfigLoader;
import java.util.Set; import net.Broken.MainBot;
import net.Broken.SlashCommand;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;
import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
/** /**
* Find and load bot's command * Find and load bot's command
@ -21,52 +22,56 @@ import java.util.Set;
public class SlashCommandLoader { public class SlashCommandLoader {
private static final Logger logger = LogManager.getLogger(); private static final Logger logger = LogManager.getLogger();
private SlashCommandLoader() {
}
/** /**
* Search all implemented Command interface class and add it to MainBot.commands HashMap * Search all implemented Command interface class and add it to MainBot.commands
* HashMap
*/ */
public static void load(BotConfigLoader config) { public static void load(BotConfigLoader config) {
logger.info("Loading Slash Command..."); logger.info("Loading Slash Command...");
Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage( Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(
"net.Broken.SlashCommands", "net.Broken.SlashCommands",
ClasspathHelper.contextClassLoader(), ClasspathHelper.contextClassLoader(),
ClasspathHelper.staticClassLoader())) ClasspathHelper.staticClassLoader())));
);
Set<Class<? extends SlashCommand>> modules = reflections.getSubTypesOf(SlashCommand.class); Set<Class<? extends SlashCommand>> modules = reflections.getSubTypesOf(SlashCommand.class);
logger.info("Find " + modules.size() + " Command:"); logger.info("Find {} Command:", modules.size());
for (Class<? extends SlashCommand> command : modules) { for (Class<? extends SlashCommand> command : modules) {
String reference = command.getName(); String reference = command.getName();
String[] splited = reference.split("\\."); String[] splited = reference.split("\\.");
String name = splited[splited.length - 1].toLowerCase(); String name = splited[splited.length - 1].toLowerCase();
if (!command.isAnnotationPresent(Ignore.class)) { if (!command.isAnnotationPresent(Ignore.class)) {
logger.info("..." + name); logger.info("...{}", name);
if (command.isAnnotationPresent(NoDev.class) && config.mode().equals("DEV")) { if (command.isAnnotationPresent(NoDev.class) && config.mode().equals("DEV")) {
logger.warn("Command disabled in dev mode"); logger.warn("Command disabled in dev mode");
} else { } else {
try { try {
MainBot.slashCommands.put(name, command.getDeclaredConstructor().newInstance()); MainBot.slashCommands.put(name, command.getDeclaredConstructor().newInstance());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | } catch (InstantiationException | IllegalAccessException | InvocationTargetException
NoSuchMethodException e) { | NoSuchMethodException e) {
logger.error("Failed to load " + name + "!"); logger.error("Failed to load {} !", name);
} }
} }
} else { } else {
logger.trace("Ignored command: " + name); logger.trace("Ignored command: {}", name);
} }
} }
} }
public static void registerSlashCommands(CommandListUpdateAction commandListUpdateAction) { public static void registerSlashCommands(CommandListUpdateAction commandListUpdateAction) {
MainBot.slashCommands.forEach((k, v) -> { MainBot.slashCommands.forEach((k, v) -> {
CommandData command = new CommandData(k, v.getDescription()); SlashCommandData command = Commands.slash(k, v.getDescription());
if (v.getOptions() != null) if (v.getOptions() != null)
command.addOptions(v.getOptions()); command.addOptions(v.getOptions());
if (v.getSubcommands() != null) { if (v.getSubcommands() != null) {
command.addSubcommands(v.getSubcommands()); command.addSubcommands(v.getSubcommands());
} }
command.setDefaultEnabled(!v.isDisableByDefault()); command.setDefaultPermissions(v.getDefaultPermissions());
commandListUpdateAction.addCommands(command); commandListUpdateAction.addCommands(command);
}); });
commandListUpdateAction.queue(); commandListUpdateAction.queue();

View File

@ -1,12 +1,12 @@
package net.Broken.Tools.DayListener; package net.Broken.Tools.DayListener;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** /**
* Day change listener * Day change listener
*/ */
@ -42,7 +42,6 @@ public class DayListener extends Thread {
} }
} }
/** /**
* Thread loop * Thread loop
*/ */

View File

@ -1,18 +1,5 @@
package net.Broken.Tools.DayListener.Listeners; package net.Broken.Tools.DayListener.Listeners;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.MainBot;
import net.Broken.SlashCommands.Over18.Madame;
import net.Broken.SpringContext;
import net.Broken.Tools.DayListener.NewDayListener;
import net.Broken.Tools.FindContentOnWebPage;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.TextChannel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@ -20,6 +7,20 @@ import java.util.Calendar;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import net.Broken.MainBot;
import net.Broken.SpringContext;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.SlashCommands.Over18.Madame;
import net.Broken.Tools.FindContentOnWebPage;
import net.Broken.Tools.DayListener.NewDayListener;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
/** /**
* Daily Listener for DailyMadame * Daily Listener for DailyMadame
*/ */
@ -44,18 +45,13 @@ public class DailyMadame implements NewDayListener {
if (day != Calendar.MONDAY && day != Calendar.SUNDAY) { if (day != Calendar.MONDAY && day != Calendar.SUNDAY) {
LocalDate now = LocalDate.now().minusDays(1); LocalDate now = LocalDate.now().minusDays(1);
String date = DateTimeFormatter.ofPattern("yyyy/MM/dd").format(now); String date = DateTimeFormatter.ofPattern("yyyy/MM/dd").format(now);
String url = "https://www.bonjourmadame.fr/" + date + "/"; String url = "https://www.bonjourmadame.fr/" + date + "/";
imgUrl = FindContentOnWebPage.doYourJob(url, "post-content", "img"); imgUrl = FindContentOnWebPage.doYourJob(url, "post-content", "img");
} else { } else {
Madame command = (Madame) MainBot.slashCommands.get("madame"); Madame command = (Madame) MainBot.slashCommands.get("madame");
imgUrl = command.poll(); imgUrl = command.poll();
} }
for (Guild guild : guilds) { for (Guild guild : guilds) {
TextChannel chanel = null; TextChannel chanel = null;
logger.debug(guild.getName()); logger.debug(guild.getName());
@ -64,17 +60,14 @@ public class DailyMadame implements NewDayListener {
for (TextChannel iterator : guild.getTextChannels()) { for (TextChannel iterator : guild.getTextChannels()) {
if (iterator.isNSFW() && iterator.canTalk()) { if (iterator.isNSFW() && iterator.canTalk()) {
chanel = iterator; chanel = iterator;
logger.debug("break: " + chanel.getName()); logger.debug("break: {}", chanel.getName());
break; break;
} }
} }
if (chanel != null) { if (chanel != null) {
chanel.sendMessage("Madame of the day :kissing_heart: \n" + imgUrl).queue(); chanel.sendMessage("Madame of the day :kissing_heart: \n" + imgUrl).queue();
} else { } else {
logger.info("No NSFW chanel found for " + guild.getName() + ", ignoring it!"); logger.info("No NSFW chanel found for {}, ignoring it!", guild.getName());
} }
} }
} }

View File

@ -1,19 +1,20 @@
package net.Broken.Tools; package net.Broken.Tools;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import java.awt.Color;
import net.Broken.Audio.UserAudioTrack;
import net.Broken.BotConfigLoader;
import net.Broken.MainBot;
import net.Broken.SpringContext;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageEmbed;
import java.awt.*;
import java.time.Instant; import java.time.Instant;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import net.Broken.BotConfigLoader;
import net.Broken.MainBot;
import net.Broken.SpringContext;
import net.Broken.Audio.UserAudioTrack;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageEmbed;
/** /**
* Pre build Message Embed * Pre build Message Embed
*/ */
@ -26,7 +27,6 @@ public class EmbedMessageUtils {
.setDescription(message); .setDescription(message);
} }
public static MessageEmbed getMusicError(String message) { public static MessageEmbed getMusicError(String message) {
return buildStandar(new EmbedBuilder() return buildStandar(new EmbedBuilder()
.setTitle(":warning: Musique Error") .setTitle(":warning: Musique Error")
@ -35,7 +35,7 @@ public class EmbedMessageUtils {
} }
public static MessageEmbed getMusicOk(String message) { public static MessageEmbed getMusicOk(String message) {
// TODO better display for different action (add icon ?) // TODO better display for different action (add icon ?)
EmbedBuilder temp = new EmbedBuilder() EmbedBuilder temp = new EmbedBuilder()
.setTitle(":loud_sound: " + message) .setTitle(":loud_sound: " + message)
.setColor(Color.green); .setColor(Color.green);
@ -53,18 +53,17 @@ public class EmbedMessageUtils {
return buildStandar(temp); return buildStandar(temp);
} }
public static MessageEmbed getMusicAdded(AudioTrackInfo info, Member member, int playlistSize){ public static MessageEmbed getMusicAdded(AudioTrackInfo info, Member member, int playlistSize) {
EmbedBuilder temp = new EmbedBuilder() EmbedBuilder temp = new EmbedBuilder()
.addField("Title", info.title, false) .addField("Title", info.title, false)
.addField("Author", info.author, false) .addField("Author", info.author, false)
.addField("Submitted by", member.getEffectiveName(), true) .addField("Submitted by", member.getEffectiveName(), true)
.setThumbnail("https://img.youtube.com/vi/" + info.identifier + "/hqdefault.jpg") .setThumbnail("https://img.youtube.com/vi/" + info.identifier + "/hqdefault.jpg")
.setColor(Color.green); .setColor(Color.green);
if(playlistSize != -1){ if (playlistSize != -1) {
temp.addField("Loaded tracks", Integer.toString(playlistSize), true) temp.addField("Loaded tracks", Integer.toString(playlistSize), true)
.setTitle(":loud_sound: Playlist added to queue"); .setTitle(":loud_sound: Playlist added to queue");
} } else {
else {
temp.setTitle(":loud_sound: Track added to queue"); temp.setTitle(":loud_sound: Track added to queue");
} }
temp.addField("URL", info.uri, false); temp.addField("URL", info.uri, false);
@ -78,10 +77,10 @@ public class EmbedMessageUtils {
.setColor(Color.red)); .setColor(Color.red));
} }
public static MessageEmbed getInternalError() { public static MessageEmbed getInternalError() {
return buildStandar( return buildStandar(
getError("I... I... I don't feel so good ~~mr stark~~... :thermometer_face: \nPlease contact my developer!") getError(
"I... I... I don't feel so good ~~mr stark~~... :thermometer_face: \nPlease contact my developer!")
.setImage("https://i.imgur.com/anKv8U5.gif")); .setImage("https://i.imgur.com/anKv8U5.gif"));
} }
@ -94,7 +93,8 @@ public class EmbedMessageUtils {
} }
public static MessageEmbed getUnautorized() { public static MessageEmbed getUnautorized() {
return buildStandar(getError("You're not powerful enough to do that slave !").setImage("https://i.imgur.com/0OSsdvW.gif")); return buildStandar(
getError("You're not powerful enough to do that slave !").setImage("https://i.imgur.com/0OSsdvW.gif"));
} }
public static MessageEmbed getLastMessageFromTextChannel(HashMap<String, String> message) { public static MessageEmbed getLastMessageFromTextChannel(HashMap<String, String> message) {
@ -118,5 +118,4 @@ public class EmbedMessageUtils {
.build(); .build();
} }
} }

View File

@ -7,47 +7,49 @@ import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
public class FindContentOnWebPage { public class FindContentOnWebPage {
/** /**
* Find picture URL on webPage * Find picture URL on webPage
* *
* @param url Web Page URL * @param url Web Page URL
* @param divClass Div class where the picture is * @param divClass Div class where the picture is
* @param htmlType HTML tag of image (img) * @param htmlType HTML tag of image (img)
* @return Picture URL * @return Picture URL
* @throws IOException * @throws IOException
*/ */
public static String doYourJob(String url, String divClass, String htmlType) throws IOException, InterruptedException { public static String doYourJob(String url, String divClass, String htmlType)
// System.out.println(url); throws IOException, InterruptedException {
String source = getSourceUrl(url); // System.out.println(url);
int divIndex = source.indexOf("class=\"" + divClass); String source = getSourceUrl(url);
String sub = source.substring(divIndex); int divIndex = source.indexOf("class=\"" + divClass);
// System.out.println(sub); String sub = source.substring(divIndex);
sub = sub.replace(divClass, ""); // System.out.println(sub);
sub = sub.substring(sub.indexOf(htmlType)); sub = sub.replace(divClass, "");
sub = sub.substring(sub.indexOf("src")); sub = sub.substring(sub.indexOf(htmlType));
sub = sub.replace("src=\"", ""); sub = sub.substring(sub.indexOf("src"));
String[] split = sub.split("\""); sub = sub.replace("src=\"", "");
// System.out.println(split[0]); String[] split = sub.split("\"");
return split[0]; // System.out.println(split[0]);
} return split[0];
}
/** /**
* Get source code of web page * Get source code of web page
* *
* @param url Web page URL * @param url Web page URL
* @return Web page source as String * @return Web page source as String
* @throws IOException * @throws IOException
*/ */
public static String getSourceUrl(String url) throws IOException, InterruptedException { public static String getSourceUrl(String url) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url)) .uri(URI.create(url))
.header("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)") .header("User-Agent",
.GET() "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")
.build(); .GET()
HttpClient client = HttpClient.newHttpClient(); .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body(); return response.body();
} }
} }

View File

@ -11,7 +11,6 @@ import org.apache.logging.log4j.Logger;
public class LimitChecker { public class LimitChecker {
static final Logger logger = LogManager.getLogger(); static final Logger logger = LogManager.getLogger();
/** /**
* Check max page url for web site like baseURL.com/number-2/ * Check max page url for web site like baseURL.com/number-2/
* *
@ -74,6 +73,5 @@ public class LimitChecker {
logger.debug("Final pass: " + number); logger.debug("Final pass: " + number);
return number; return number;
} }
} }

View File

@ -1,18 +1,19 @@
package net.Broken.Tools.Random.Data; package net.Broken.Tools.Random.Data;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List; import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public record RandomData(String jsonrpc, String method, int id, Params params, Error error, Result result) { public record RandomData(String jsonrpc, String method, int id, Params params, Error error, Result result) {
public record Params(String apiKey, int n, int min, int max, boolean replacement) { public record Params(String apiKey, int n, int min, int max, boolean replacement) {
} }
public record Error(long code, String message, Object data){}; public record Error(long code, String message, Object data) {
public record Result(Random random, String bitsUsed, String bitsLeft, String requestsLeft, String advisoryDelay){ };
public record Random(List<Integer> data, String completionTime){};
public record Result(Random random, String bitsUsed, String bitsLeft, String requestsLeft, String advisoryDelay) {
public record Random(List<Integer> data, String completionTime) {
};
} }
} }

View File

@ -1,9 +1,10 @@
package net.Broken.Tools.Random; package net.Broken.Tools.Random;
import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException;
import net.Broken.BotConfigLoader; import java.io.InputStream;
import net.Broken.SpringContext; import java.nio.charset.StandardCharsets;
import net.Broken.Tools.Random.Data.RandomData; import java.util.List;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
@ -14,16 +15,18 @@ import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.io.IOException; import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.InputStream;
import java.nio.charset.StandardCharsets; import net.Broken.BotConfigLoader;
import java.util.List; import net.Broken.SpringContext;
import net.Broken.Tools.Random.Data.RandomData;
public class TrueRandom { public class TrueRandom {
private static final TrueRandom INSTANCE = new TrueRandom(); private static final TrueRandom INSTANCE = new TrueRandom();
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
private final String apiKey; private final String apiKey;
private TrueRandom() { private TrueRandom() {
apiKey = SpringContext.getAppContext().getBean(BotConfigLoader.class).randomApiKey(); apiKey = SpringContext.getAppContext().getBean(BotConfigLoader.class).randomApiKey();
} }
@ -34,10 +37,11 @@ public class TrueRandom {
public List<Integer> getNumbers(int min, int max) throws IOException { public List<Integer> getNumbers(int min, int max) throws IOException {
// TODO Migrate to native http client // TODO Migrate to native http client
HttpClient httpClient = HttpClientBuilder.create().build(); HttpClient httpClient = HttpClientBuilder.create().build();
RandomData postData = new RandomData("2.0", "generateIntegers", 41, new RandomData.Params(apiKey, 50, min, max, (max - min) < 50), null, null); RandomData postData = new RandomData("2.0", "generateIntegers", 41,
new RandomData.Params(apiKey, 50, min, max, (max - min) < 50), null, null);
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
StringEntity entity = new StringEntity(mapper.writeValueAsString(postData), ContentType.APPLICATION_JSON); StringEntity entity = new StringEntity(mapper.writeValueAsString(postData), ContentType.APPLICATION_JSON);
@ -55,7 +59,6 @@ public class TrueRandom {
throw new IOException(); throw new IOException();
} }
InputStream responseIS = response.getEntity().getContent(); InputStream responseIS = response.getEntity().getContent();
String content = IOUtils.toString(responseIS, StandardCharsets.UTF_8); String content = IOUtils.toString(responseIS, StandardCharsets.UTF_8);

View File

@ -24,19 +24,18 @@ public class Redirection {
System.setProperty("http.agent", "Googlebot"); System.setProperty("http.agent", "Googlebot");
HttpURLConnection con = (HttpURLConnection) new URL(urlString).openConnection(); HttpURLConnection con = (HttpURLConnection) new URL(urlString).openConnection();
con.setRequestProperty("User-Agent", "Googlebot/2.1 (+http://www.googlebot.com/bot.html)"); con.setRequestProperty("User-Agent", "Googlebot/2.1 (+http://www.googlebot.com/bot.html)");
//System.out.println( "orignal url: " + con.getURL() ); // System.out.println( "orignal url: " + con.getURL() );
con.connect(); con.connect();
//System.out.println( "connected url: " + con.getURL() ); // System.out.println( "connected url: " + con.getURL() );
InputStream is = null; InputStream is = null;
if (con.getResponseCode() != 200) if (con.getResponseCode() != 200)
return ""; return "";
is = con.getInputStream(); is = con.getInputStream();
String urlReturn = con.getURL().toString(); String urlReturn = con.getURL().toString();
//System.out.println( "redirected url: " + con.getURL() ); // System.out.println( "redirected url: " + con.getURL() );
is.close(); is.close();
return urlReturn; return urlReturn;
} }
} }

View File

@ -1,111 +1,102 @@
package net.Broken.Tools.Settings; package net.Broken.Tools.Settings;
import net.Broken.Api.Data.Settings.SettingDescriber;
import net.Broken.Api.Data.Settings.SettingGroup;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.Broken.Api.Data.Settings.SettingDescriber;
import net.Broken.Api.Data.Settings.SettingGroup;
public class SettingDescriptionBuilder { public class SettingDescriptionBuilder {
public List<SettingGroup> build(){ public List<SettingGroup> build() {
List<SettingGroup> toReturn = new ArrayList<>(); List<SettingGroup> toReturn = new ArrayList<>();
toReturn.add(getWelcomeGroup()); toReturn.add(getWelcomeGroup());
toReturn.add(getDefaultRoleGroup()); toReturn.add(getDefaultRoleGroup());
toReturn.add(getAutoVoiceChannelGroup()); toReturn.add(getAutoVoiceChannelGroup());
toReturn.add(getDailyGroup()); toReturn.add(getDailyGroup());
return toReturn; return toReturn;
} }
private SettingGroup getWelcomeGroup() {
SettingDescriber mainField = new SettingDescriber(
"welcome_enable",
"Enable Welcome Message",
null,
SettingDescriber.TYPE.BOOL
);
List<SettingDescriber> fields = new ArrayList<>(); private SettingGroup getWelcomeGroup() {
fields.add(new SettingDescriber( SettingDescriber mainField = new SettingDescriber(
"welcome_chanel_id", "welcome_enable",
"Welcome Message chanel", "Enable Welcome Message",
null, null,
SettingDescriber.TYPE.TEXT_CHANNEL SettingDescriber.TYPE.BOOL);
));
fields.add(new SettingDescriber(
"welcome_message",
"Welcome Message",
null,
SettingDescriber.TYPE.STRING
));
List<SettingDescriber> fields = new ArrayList<>();
fields.add(new SettingDescriber(
"welcome_chanel_id",
"Welcome Message chanel",
null,
SettingDescriber.TYPE.TEXT_CHANNEL));
fields.add(new SettingDescriber(
"welcome_message",
"Welcome Message",
null,
SettingDescriber.TYPE.STRING));
return new SettingGroup( return new SettingGroup(
"Welcome Message", "Welcome Message",
mainField, mainField,
fields); fields);
} }
private SettingGroup getDefaultRoleGroup() { private SettingGroup getDefaultRoleGroup() {
SettingDescriber mainField = new SettingDescriber( SettingDescriber mainField = new SettingDescriber(
"default_role", "default_role",
"Enable Default Role", "Enable Default Role",
null, null,
SettingDescriber.TYPE.BOOL SettingDescriber.TYPE.BOOL);
);
List<SettingDescriber> fields = new ArrayList<>(); List<SettingDescriber> fields = new ArrayList<>();
fields.add(new SettingDescriber( fields.add(new SettingDescriber(
"default_role_id", "default_role_id",
"Default Role", "Default Role",
null, null,
SettingDescriber.TYPE.ROLE SettingDescriber.TYPE.ROLE));
));
return new SettingGroup( return new SettingGroup(
"Default Role", "Default Role",
mainField, mainField,
fields); fields);
} }
private SettingGroup getDailyGroup() { private SettingGroup getDailyGroup() {
List<SettingDescriber> fields = new ArrayList<>(); List<SettingDescriber> fields = new ArrayList<>();
fields.add(new SettingDescriber( fields.add(new SettingDescriber(
"daily_madame", "daily_madame",
"[NSFW] Enable Daily Madame Message", "[NSFW] Enable Daily Madame Message",
null, null,
SettingDescriber.TYPE.BOOL SettingDescriber.TYPE.BOOL));
));
return new SettingGroup( return new SettingGroup(
"Daily", "Daily",
null, null,
fields); fields);
} }
private SettingGroup getAutoVoiceChannelGroup() { private SettingGroup getAutoVoiceChannelGroup() {
SettingDescriber mainField = new SettingDescriber( SettingDescriber mainField = new SettingDescriber(
"auto_voice", "auto_voice",
"Enable Auto Create Voice Chanel", "Enable Auto Create Voice Chanel",
null, null,
SettingDescriber.TYPE.BOOL SettingDescriber.TYPE.BOOL);
);
List<SettingDescriber> fields = new ArrayList<>(); List<SettingDescriber> fields = new ArrayList<>();
fields.add(new SettingDescriber( fields.add(new SettingDescriber(
"auto_voice_base_channel", "auto_voice_base_channel",
"Base Voice Channel For Auto Create", "Base Voice Channel For Auto Create",
"If someone joint this channel, a new voice channel will be created with the same settings.", "If someone joint this channel, a new voice channel will be created with the same settings.",
SettingDescriber.TYPE.VOICE_CHANNEL SettingDescriber.TYPE.VOICE_CHANNEL));
)); fields.add(new SettingDescriber(
fields.add(new SettingDescriber( "auto_voice_channel_title",
"auto_voice_channel_title", "Auto Created Voice Channel title",
"Auto Created Voice Channel title", "Auto created voice channel will use this title, @count will be replaced by the channel count.",
"Auto created voice channel will use this title, @count will be replaced by the channel count.", SettingDescriber.TYPE.STRING));
SettingDescriber.TYPE.STRING
));
return new SettingGroup( return new SettingGroup(
"Auto Voice Channel", "Auto Voice Channel",
mainField, mainField,
fields); fields);
} }
} }

View File

@ -1,12 +1,13 @@
package net.Broken.Tools.Settings; package net.Broken.Tools.Settings;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.Broken.Api.Data.Settings.Value; import net.Broken.Api.Data.Settings.Value;
import net.Broken.DB.Entity.GuildPreferenceEntity; import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository; import net.Broken.DB.Repository.GuildPreferenceRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.List;
public class SettingSaver { public class SettingSaver {
private final GuildPreferenceRepository guildPreferenceRepository; private final GuildPreferenceRepository guildPreferenceRepository;
@ -28,16 +29,16 @@ public class SettingSaver {
private void setValue(Value value) { private void setValue(Value value) {
switch (value.id()) { switch (value.id()) {
// WELCOME // WELCOME
case "welcome_enable" -> guildPreference.setWelcome((Boolean) value.value()); case "welcome_enable" -> guildPreference.setWelcome((Boolean) value.value());
case "welcome_chanel_id" -> guildPreference.setWelcomeChanelID((String) value.value()); case "welcome_chanel_id" -> guildPreference.setWelcomeChanelID((String) value.value());
case "welcome_message" -> guildPreference.setWelcomeMessage((String) value.value()); case "welcome_message" -> guildPreference.setWelcomeMessage((String) value.value());
// DEFAULT ROLE // DEFAULT ROLE
case "default_role" -> guildPreference.setDefaultRole((Boolean) value.value()); case "default_role" -> guildPreference.setDefaultRole((Boolean) value.value());
case "default_role_id" -> guildPreference.setDefaultRoleId((String) value.value()); case "default_role_id" -> guildPreference.setDefaultRoleId((String) value.value());
// DAILY // DAILY
case "daily_madame" -> guildPreference.setDailyMadame((Boolean) value.value()); case "daily_madame" -> guildPreference.setDailyMadame((Boolean) value.value());
// AUTO VOICE CHAN // AUTO VOICE CHAN
case "auto_voice" -> guildPreference.setAutoVoice((Boolean) value.value()); case "auto_voice" -> guildPreference.setAutoVoice((Boolean) value.value());
case "auto_voice_base_channel" -> guildPreference.setAutoVoiceChannelID((String) value.value()); case "auto_voice_base_channel" -> guildPreference.setAutoVoiceChannelID((String) value.value());
case "auto_voice_channel_title" -> guildPreference.setAutoVoiceChannelTitle((String) value.value()); case "auto_voice_channel_title" -> guildPreference.setAutoVoiceChannelTitle((String) value.value());

View File

@ -1,89 +1,71 @@
package net.Broken.Tools.Settings; package net.Broken.Tools.Settings;
import net.Broken.Api.Data.Settings.Value;
import net.Broken.DB.Entity.GuildPreferenceEntity;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.Broken.Api.Data.Settings.Value;
import net.Broken.DB.Entity.GuildPreferenceEntity;
public class SettingValueBuilder { public class SettingValueBuilder {
private final GuildPreferenceEntity guildPreference; private final GuildPreferenceEntity guildPreference;
public SettingValueBuilder(GuildPreferenceEntity guildPreference) { public SettingValueBuilder(GuildPreferenceEntity guildPreference) {
this.guildPreference = guildPreference; this.guildPreference = guildPreference;
} }
public List<Value> build() { public List<Value> build() {
List<Value> values = new ArrayList<>(getWelcomeValues(guildPreference)); List<Value> values = new ArrayList<>(getWelcomeValues(guildPreference));
values.addAll(getDefaultRoleValues(guildPreference)); values.addAll(getDefaultRoleValues(guildPreference));
values.addAll(getDailyValues(guildPreference)); values.addAll(getDailyValues(guildPreference));
values.addAll(getAutoVoiceChannelValues(guildPreference)); values.addAll(getAutoVoiceChannelValues(guildPreference));
return values; return values;
} }
private List<Value> getWelcomeValues(GuildPreferenceEntity pref) { private List<Value> getWelcomeValues(GuildPreferenceEntity pref) {
List<Value> toReturn = new ArrayList<>(); List<Value> toReturn = new ArrayList<>();
toReturn.add(new Value( toReturn.add(new Value(
"welcome_enable", "welcome_enable",
pref.isWelcome() pref.isWelcome()));
) toReturn.add(new Value(
); "welcome_chanel_id",
toReturn.add(new Value( pref.getWelcomeChanelID()));
"welcome_chanel_id", toReturn.add(new Value(
pref.getWelcomeChanelID() "welcome_message",
) pref.getWelcomeMessage()));
); return toReturn;
toReturn.add(new Value( }
"welcome_message",
pref.getWelcomeMessage()
)
);
return toReturn;
}
private List<Value> getDefaultRoleValues(GuildPreferenceEntity pref) { private List<Value> getDefaultRoleValues(GuildPreferenceEntity pref) {
List<Value> toReturn = new ArrayList<>(); List<Value> toReturn = new ArrayList<>();
toReturn.add(new Value( toReturn.add(new Value(
"default_role", "default_role",
pref.isDefaultRole() pref.isDefaultRole()));
) toReturn.add(new Value(
); "default_role_id",
toReturn.add(new Value( pref.getDefaultRoleId()));
"default_role_id", return toReturn;
pref.getDefaultRoleId() }
)
);
return toReturn;
}
private List<Value> getDailyValues(GuildPreferenceEntity pref) { private List<Value> getDailyValues(GuildPreferenceEntity pref) {
List<Value> toReturn = new ArrayList<>(); List<Value> toReturn = new ArrayList<>();
toReturn.add(new Value( toReturn.add(new Value(
"daily_madame", "daily_madame",
pref.isDailyMadame() pref.isDailyMadame()));
) return toReturn;
); }
return toReturn;
}
private List<Value> getAutoVoiceChannelValues(GuildPreferenceEntity pref) { private List<Value> getAutoVoiceChannelValues(GuildPreferenceEntity pref) {
List<Value> toReturn = new ArrayList<>(); List<Value> toReturn = new ArrayList<>();
toReturn.add(new Value( toReturn.add(new Value(
"auto_voice", "auto_voice",
pref.isAutoVoice() pref.isAutoVoice()));
) toReturn.add(new Value(
); "auto_voice_base_channel",
toReturn.add(new Value( pref.getAutoVoiceChannelID()));
"auto_voice_base_channel", toReturn.add(new Value(
pref.getAutoVoiceChannelID() "auto_voice_channel_title",
) pref.getAutoVoiceChannelTitle()));
); return toReturn;
toReturn.add(new Value( }
"auto_voice_channel_title",
pref.getAutoVoiceChannelTitle()
)
);
return toReturn;
}
} }

View File

@ -2,7 +2,6 @@ package net.Broken.Tools;
import net.Broken.DB.Entity.GuildPreferenceEntity; import net.Broken.DB.Entity.GuildPreferenceEntity;
import net.Broken.DB.Repository.GuildPreferenceRepository; import net.Broken.DB.Repository.GuildPreferenceRepository;
import net.Broken.DB.Repository.UserRepository;
import net.Broken.SpringContext; import net.Broken.SpringContext;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -14,13 +13,10 @@ public class SettingsUtils {
private static SettingsUtils INSTANCE; private static SettingsUtils INSTANCE;
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
private final GuildPreferenceRepository guildPreferenceRepository; private final GuildPreferenceRepository guildPreferenceRepository;
private final UserRepository userRepository;
private SettingsUtils() { private SettingsUtils() {
ApplicationContext context = SpringContext.getAppContext(); ApplicationContext context = SpringContext.getAppContext();
guildPreferenceRepository = (GuildPreferenceRepository) context.getBean("guildPreferenceRepository"); guildPreferenceRepository = (GuildPreferenceRepository) context.getBean("guildPreferenceRepository");
userRepository = (UserRepository) context.getBean("userRepository");
} }
public static SettingsUtils getInstance() { public static SettingsUtils getInstance() {
@ -28,8 +24,8 @@ public class SettingsUtils {
} }
public GuildPreferenceEntity getPreference(Guild guild) { public GuildPreferenceEntity getPreference(Guild guild) {
return guildPreferenceRepository.findByGuildId(guild.getId()).orElseGet(()->{ return guildPreferenceRepository.findByGuildId(guild.getId()).orElseGet(() -> {
logger.info("Generate default pref for " + guild.getName()); logger.info("Generate default pref for {}", guild.getName());
return guildPreferenceRepository.save(GuildPreferenceEntity.getDefault(guild.getId())); return guildPreferenceRepository.save(GuildPreferenceEntity.getDefault(guild.getId()));
}); });
} }

View File

@ -1,10 +1,10 @@
package net.Broken.Tools; package net.Broken.Tools;
import java.util.ArrayList;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.ArrayList;
public class TimeConvertor { public class TimeConvertor {
static Logger logger = LogManager.getLogger(); static Logger logger = LogManager.getLogger();

View File

@ -1,11 +1,20 @@
package net.Broken.Tools.UserManager.Stats; package net.Broken.Tools.UserManager.Stats;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import net.Broken.MainBot;
import net.Broken.SpringContext;
import net.Broken.DB.Entity.UserEntity; import net.Broken.DB.Entity.UserEntity;
import net.Broken.DB.Entity.UserStats; import net.Broken.DB.Entity.UserStats;
import net.Broken.DB.Repository.UserRepository; import net.Broken.DB.Repository.UserRepository;
import net.Broken.DB.Repository.UserStatsRepository; import net.Broken.DB.Repository.UserStatsRepository;
import net.Broken.MainBot;
import net.Broken.SpringContext;
import net.Broken.Tools.CacheTools; import net.Broken.Tools.CacheTools;
import net.Broken.Tools.EmbedMessageUtils; import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
@ -13,14 +22,6 @@ import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class UserStatsUtils { public class UserStatsUtils {
@ -28,7 +29,6 @@ public class UserStatsUtils {
static final double XP_PER_MESSAGE = 4; static final double XP_PER_MESSAGE = 4;
static final double XP_PER_API_COUNT = 1; static final double XP_PER_API_COUNT = 1;
private static UserStatsUtils INSTANCE = new UserStatsUtils(); private static UserStatsUtils INSTANCE = new UserStatsUtils();
private final UserStatsRepository userStatsRepository; private final UserStatsRepository userStatsRepository;
private final UserRepository userRepository; private final UserRepository userRepository;
@ -40,7 +40,6 @@ public class UserStatsUtils {
userStatsRepository = (UserStatsRepository) context.getBean("userStatsRepository"); userStatsRepository = (UserStatsRepository) context.getBean("userStatsRepository");
userRepository = (UserRepository) context.getBean("userRepository"); userRepository = (UserRepository) context.getBean("userRepository");
} }
public static UserStatsUtils getINSTANCE() { public static UserStatsUtils getINSTANCE() {
@ -51,7 +50,7 @@ public class UserStatsUtils {
public List<UserStats> getUserStats(UserEntity userEntity) { public List<UserStats> getUserStats(UserEntity userEntity) {
User jdaUser = CacheTools.getJdaUser(userEntity); User jdaUser = CacheTools.getJdaUser(userEntity);
//TODO clean database for deleted users // TODO clean database for deleted users
if (jdaUser == null) { if (jdaUser == null) {
logger.warn("jdaUser is null, can't find discord user ????"); logger.warn("jdaUser is null, can't find discord user ????");
@ -60,16 +59,17 @@ public class UserStatsUtils {
logger.debug(userEntity); logger.debug(userEntity);
logger.debug(userEntity.getUserStats()); logger.debug(userEntity.getUserStats());
if (userEntity.getUserStats() == null || userEntity.getUserStats().size() == 0 || userEntity.getUserStats().size() < jdaUser.getMutualGuilds().size()) { if (userEntity.getUserStats() == null || userEntity.getUserStats().isEmpty()
logger.debug("Stats not found for " + userEntity.getUsername()); || userEntity.getUserStats().size() < jdaUser.getMutualGuilds().size()) {
logger.debug("Stats not found for {}", userEntity.getUsername());
List<UserStats> stats; List<UserStats> stats;
if (userEntity.getUserStats() == null || userEntity.getUserStats().size() == 0) { if (userEntity.getUserStats() == null || userEntity.getUserStats().isEmpty()) {
logger.debug("No stats found for user " + jdaUser.getName() + ", use blank."); logger.debug("No stats found for user {}, use blank.", jdaUser.getName());
logger.debug("Creating stats for guilds: "); logger.debug("Creating stats for guilds: ");
stats = new ArrayList<>(); stats = new ArrayList<>();
for (Guild guid : jdaUser.getMutualGuilds()) { for (Guild guid : jdaUser.getMutualGuilds()) {
logger.debug("..." + guid.getName()); logger.debug("...{}", guid.getName());
stats.add(new UserStats(guid.getId(), userEntity)); stats.add(new UserStats(guid.getId(), userEntity));
} }
} else { } else {
@ -81,7 +81,7 @@ public class UserStatsUtils {
for (Guild guid : jdaUser.getMutualGuilds()) { for (Guild guid : jdaUser.getMutualGuilds()) {
logger.debug(guid.getName()); logger.debug(guid.getName());
if (!guildStat.contains(guid.getId())) { if (!guildStat.contains(guid.getId())) {
logger.debug("Guild " + guid.getName() + " stats don't exist"); logger.debug("Guild {} stats don't exist", guid.getName());
stats.add(new UserStats(guid.getId(), userEntity)); stats.add(new UserStats(guid.getId(), userEntity));
} }
} }
@ -102,14 +102,14 @@ public class UserStatsUtils {
} }
public UserStats getGuildUserStats(Member member) { public UserStats getGuildUserStats(Member member) {
UserEntity userEntity = userRepository.findByDiscordId(member.getUser().getId()) UserEntity userEntity = userRepository.findByDiscordId(member.getUser().getId())
.orElseGet(() -> genUserEntity(member.getUser())); .orElseGet(() -> genUserEntity(member.getUser()));
List<UserStats> userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, member.getGuild().getId()); List<UserStats> userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, member.getGuild().getId());
if (userStatsList.size() == 0) { if (userStatsList.isEmpty()) {
logger.debug("User stats not found for user " + userEntity.getUsername() + " guild: " + member.getGuild().getId()); logger.debug("User stats not found for user {} guild: {}", userEntity.getUsername(),
member.getGuild().getId());
getUserStats(userEntity); getUserStats(userEntity);
userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, member.getGuild().getId()); userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, member.getGuild().getId());
} }
@ -119,51 +119,42 @@ public class UserStatsUtils {
public UserStats getGuildUserStats(UserEntity userEntity, String guildId) { public UserStats getGuildUserStats(UserEntity userEntity, String guildId) {
List<UserStats> userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, guildId); List<UserStats> userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, guildId);
if (userStatsRepository.findByUserAndGuildId(userEntity, guildId).size() == 0) { if (userStatsRepository.findByUserAndGuildId(userEntity, guildId).isEmpty()) {
logger.debug("User stats not found for user " + userEntity.getUsername() + " guild: " + guildId); logger.debug("User stats not found for user {} guild: {}", userEntity.getUsername(), guildId);
getUserStats(userEntity); getUserStats(userEntity);
userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, guildId); userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, guildId);
} }
return userStatsList.get(0); return userStatsList.get(0);
} }
public void addMessageCount(Member member) { public void addMessageCount(Member member) {
UserStats userStats = getGuildUserStats(member); UserStats userStats = getGuildUserStats(member);
userStats.setMessageCount(userStats.getMessageCount() + 1); userStats.setMessageCount(userStats.getMessageCount() + 1);
userStatsRepository.save(userStats); userStatsRepository.save(userStats);
} }
public void addApiCount(UserEntity userEntity, String guildId) { public void addApiCount(UserEntity userEntity, String guildId) {
UserStats userStats = getGuildUserStats(userEntity, guildId); UserStats userStats = getGuildUserStats(userEntity, guildId);
userStats.setApiCommandCount(userStats.getApiCommandCount() + 1); userStats.setApiCommandCount(userStats.getApiCommandCount() + 1);
userStatsRepository.save(userStats); userStatsRepository.save(userStats);
} }
private void addVocalCount(Member member) { private void addVocalCount(Member member) {
UserStats userStats = getGuildUserStats(member); UserStats userStats = getGuildUserStats(member);
userStats.setVocalTime(userStats.getVocalTime() + 10); userStats.setVocalTime(userStats.getVocalTime() + 10);
userStatsRepository.save(userStats); userStatsRepository.save(userStats);
} }
private UserEntity genUserEntity(User user) { private UserEntity genUserEntity(User user) {
UserEntity userEntity = new UserEntity(user); UserEntity userEntity = new UserEntity(user);
return userRepository.save(userEntity); return userRepository.save(userEntity);
} }
public GuildStatsPack getStatPack(UserEntity userEntity, String guildId) { public GuildStatsPack getStatPack(UserEntity userEntity, String guildId) {
UserStats userStats = getGuildUserStats(userEntity, guildId);
GuildStats selfGuildStats = null; GuildStats selfGuildStats = null;
List<UserStats> allStats = userStatsRepository.findByGuildId(guildId); List<UserStats> allStats = userStatsRepository.findByGuildId(guildId);
@ -177,23 +168,26 @@ public class UserStatsUtils {
continue; continue;
} }
String avatar = member.getUser().getAvatarUrl(); String avatar = member.getUser().getAvatarUrl();
GuildStats temp = new GuildStats(stats.getUser().getUsername(), 0, avatar, stats.getVocalTime(), stats.getMessageCount(), stats.getApiCommandCount()); GuildStats temp = new GuildStats(stats.getUser().getUsername(), 0, avatar, stats.getVocalTime(),
stats.getMessageCount(), stats.getApiCommandCount());
if (stats.getUser().getId().equals(userEntity.getId())) { if (stats.getUser().getId().equals(userEntity.getId())) {
selfGuildStats = temp; selfGuildStats = temp;
} }
ranked.add(temp); ranked.add(temp);
} }
if (needCache.size() != 0) { if (!needCache.isEmpty()) {
logger.info("Cache mismatch, loading all guild"); logger.info("Cache mismatch, loading all guild");
MainBot.jda.getGuildById(guildId).loadMembers().get(); MainBot.jda.getGuildById(guildId).loadMembers().get();
for (UserStats stats : needCache) { for (UserStats stats : needCache) {
Member member = guild.getMemberById(stats.getUser().getDiscordId()); Member member = guild.getMemberById(stats.getUser().getDiscordId());
if (member == null) { if (member == null) {
logger.warn("Can't find member '" + stats.getUser().getUsername() + "'after load, User leave the guild ?"); logger.warn("Can't find member '{}'after load, User leave the guild ?",
stats.getUser().getUsername());
continue; continue;
} }
String avatar = member.getUser().getAvatarUrl(); String avatar = member.getUser().getAvatarUrl();
GuildStats temp = new GuildStats(stats.getUser().getUsername(), 0, avatar, stats.getVocalTime(), stats.getMessageCount(), stats.getApiCommandCount()); GuildStats temp = new GuildStats(stats.getUser().getUsername(), 0, avatar, stats.getVocalTime(),
stats.getMessageCount(), stats.getApiCommandCount());
if (stats.getUser().getId().equals(userEntity.getId())) { if (stats.getUser().getId().equals(userEntity.getId())) {
selfGuildStats = temp; selfGuildStats = temp;
} }
@ -212,7 +206,6 @@ public class UserStatsUtils {
} }
public MessageEmbed getRankMessage(Member member) { public MessageEmbed getRankMessage(Member member) {
UserStats userStats = getGuildUserStats(member); UserStats userStats = getGuildUserStats(member);
GuildStatsPack pack = getStatPack(userStats.getUser(), member.getGuild().getId()); GuildStatsPack pack = getStatPack(userStats.getUser(), member.getGuild().getId());
@ -222,7 +215,8 @@ public class UserStatsUtils {
if (i >= 6) { if (i >= 6) {
break; break;
} }
stringBuilder.append(i).append(". ").append(stats.userName).append(" with ").append(stats.total).append(" points!").append("\n"); stringBuilder.append(i).append(". ").append(stats.userName).append(" with ").append(stats.total)
.append(" points!").append("\n");
i++; i++;
} }
@ -238,7 +232,6 @@ public class UserStatsUtils {
default -> pack.selfStats().rank + "th"; default -> pack.selfStats().rank + "th";
}; };
embedBuilder.addField("Your stats:", rank + " with " + pack.selfStats().total + " points", false); embedBuilder.addField("Your stats:", rank + " with " + pack.selfStats().total + " points", false);
return EmbedMessageUtils.buildStandar(embedBuilder); return EmbedMessageUtils.buildStandar(embedBuilder);
@ -253,14 +246,13 @@ public class UserStatsUtils {
@Override @Override
public void run() { public void run() {
while (member.getVoiceState().inVoiceChannel()) { while (member.getVoiceState().inAudioChannel()) {
try { try {
Thread.sleep(10000); Thread.sleep(10000);
if (member.getVoiceState().inVoiceChannel()) if (member.getVoiceState().inAudioChannel())
if (member.getGuild().getAfkChannel() != member.getVoiceState().getChannel()) if (member.getGuild().getAfkChannel() != member.getVoiceState().getChannel())
UserStatsUtils.getINSTANCE().addVocalCount(member); UserStatsUtils.getINSTANCE().addVocalCount(member);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -269,5 +261,4 @@ public class UserStatsUtils {
} }
} }
} }

View File

@ -1,26 +0,0 @@
package net.Broken.Tools.UserManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class UserUtils {
private static final UserUtils INSTANCE = new UserUtils();
private final Logger logger = LogManager.getLogger();
/**
* Private default constructor
*/
private UserUtils() {
}
/**
* Singleton
*
* @return Unique UserUtils instance
*/
public static UserUtils getInstance() {
return INSTANCE;
}
}

View File

@ -12,11 +12,11 @@ public class VersionLoader {
@Value("${git.commit.id.abbrev}") @Value("${git.commit.id.abbrev}")
private String commitId; private String commitId;
public String getVersion(){ public String getVersion() {
String version; String version;
if(tags.isEmpty()){ if (tags.isEmpty()) {
version = "DEV-" + branch + "-" + commitId; version = "DEV-" + branch + "-" + commitId;
}else{ } else {
version = tags; version = tags;
} }
return version; return version;

View File

@ -244,37 +244,6 @@ databaseChangeLog:
name: playlist_entity_id name: playlist_entity_id
type: INT type: INT
tableName: track_entity tableName: track_entity
- changeSet:
id: 1653065037086-8
author: seb65 (generated)
changes:
- createTable:
columns:
- column:
autoIncrement: true
constraints:
nullable: false
primaryKey: true
name: id
type: INT
- column:
name: api_token
type: VARCHAR(255)
- column:
name: jda_id
type: VARCHAR(255)
- column:
name: name
type: VARCHAR(255)
- column:
name: password
type: VARCHAR(255)
- column:
constraints:
nullable: false
name: is_bot_admin
type: BIT
tableName: user_entity
- changeSet: - changeSet:
id: 1653065037086-10 id: 1653065037086-10