Compare commits

..

No commits in common. "57b4583fd7b6aff47af033fbd870283da54f9b55" and "55c5e54e0ac142984759d13c37086fce3387c9d0" have entirely different histories.

78 changed files with 1584 additions and 1292 deletions

View File

@ -16,10 +16,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v3
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@v4 - uses: actions/checkout@v3
- name: Download artifact - name: Download artifact
uses: actions/download-artifact@v3.0.2 uses: actions/download-artifact@v3.0.0
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@v3 uses: docker/setup-buildx-action@v2
- name: Login to ghcr.io - name: Login to ghcr.io
uses: docker/login-action@v3 uses: docker/login-action@v2
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@v5 uses: docker/build-push-action@v3
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@v4 - uses: actions/checkout@v3
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v3
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@v4 - uses: actions/checkout@v3
- name: Download artifact - name: Download artifact
uses: actions/download-artifact@v3.0.2 uses: actions/download-artifact@v3.0.0
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@v3 uses: docker/setup-buildx-action@v2
- name: Login to ghcr.io - name: Login to ghcr.io
uses: docker/login-action@v3 uses: docker/login-action@v2
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@v5 uses: docker/build-push-action@v3
with: with:
push: true push: true
context: . context: .

View File

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

View File

@ -1,10 +1,10 @@
plugins { plugins {
id 'org.springframework.boot' version '3.2.0' id 'org.springframework.boot' version '2.7.2'
id 'io.spring.dependency-management' version '1.1.4' id 'io.spring.dependency-management' version '1.0.12.RELEASE'
id 'java' id 'java'
id 'groovy' id 'groovy'
id 'org.liquibase.gradle' version '2.2.1' id 'org.liquibase.gradle' version '2.1.1'
id "nebula.lint" version "19.0.1" id "nebula.lint" version "17.7.0"
id "com.gorylenko.gradle-git-properties" version "2.4.1" id "com.gorylenko.gradle-git-properties" version "2.4.1"
} }
@ -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.12.1') implementation('io.micrometer:micrometer-registry-prometheus:1.9.2')
implementation('org.springdoc:springdoc-openapi-ui:1.7.0') implementation('org.springdoc:springdoc-openapi-ui:1.6.9')
implementation('org.springdoc:springdoc-openapi-security:1.7.0') implementation('org.springdoc:springdoc-openapi-security:1.6.9')
implementation('org.liquibase:liquibase-core') implementation('org.liquibase:liquibase-core')
implementation('io.jsonwebtoken:jjwt-api:0.12.3') implementation('io.jsonwebtoken:jjwt-api:0.11.5')
implementation('io.jsonwebtoken:jjwt-impl:0.12.3') implementation('io.jsonwebtoken:jjwt-impl:0.11.5')
implementation('io.jsonwebtoken:jjwt-jackson:0.12.3') implementation('io.jsonwebtoken:jjwt-jackson:0.11.5')
implementation('com.sedmelluq:lavaplayer:1.3.78') implementation('com.sedmelluq:lavaplayer:1.3.78')
implementation('net.dv8tion:JDA:5.0.0-beta.18') implementation('net.dv8tion:JDA:4.4.1_353')
implementation(platform("org.apache.logging.log4j:log4j-bom:2.22.0")) implementation(platform("org.apache.logging.log4j:log4j-bom:2.18.0"))
implementation group: 'org.hibernate', name: 'hibernate-validator', version: '8.0.1.Final' implementation group: 'org.hibernate', name: 'hibernate-validator', version: '7.0.4.Final'
// Use MySQL Connector-J // Use MySQL Connector-J
implementation('mysql:mysql-connector-java:8.0.33') implementation('mysql:mysql-connector-java:8.0.30')
implementation('org.reflections:reflections:0.10.2') implementation('org.reflections:reflections:0.10.2')
implementation('org.apache.commons:commons-lang3:3.14.0') implementation('org.apache.commons:commons-lang3:3.12.0')
liquibaseRuntime('org.liquibase:liquibase-core:4.25.0') liquibaseRuntime('org.liquibase:liquibase-core:4.14.0')
liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:3.0.3') liquibaseRuntime('org.liquibase:liquibase-groovy-dsl:3.0.2')
liquibaseRuntime('mysql:mysql-connector-java:8.0.33') liquibaseRuntime('mysql:mysql-connector-java:8.0.30')
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.25.0' liquibaseRuntime group: 'org.liquibase.ext', name: 'liquibase-hibernate5', version: '4.14.0'
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:5.0.0-beta.18' liquibaseRuntime 'net.dv8tion:JDA:4.4.0_352'
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,7 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

282
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/bin/sh #!/usr/bin/env sh
# #
# Copyright © 2015-2021 the original authors. # Copyright 2015 the original author or 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,99 +17,67 @@
# #
############################################################################## ##############################################################################
# ##
# Gradle start up script for POSIX generated by Gradle. ## Gradle start up script for UN*X
# ##
# 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
app_path=$0 PRG="$0"
# Need this for relative symlinks.
# Need this for daisy-chained symlinks. while [ -h "$PRG" ] ; do
while ls=`ls -ld "$PRG"`
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path link=`expr "$ls" : '.*-> \(.*\)$'`
[ -h "$app_path" ] if expr "$link" : '/.*' > /dev/null; then
do PRG="$link"
ls=$( ls -ld "$app_path" ) else
link=${ls#*' -> '} PRG=`dirname "$PRG"`"/$link"
case $link in #( fi
/*) 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
# This is normally unused APP_NAME="Gradle"
# shellcheck disable=SC2034 APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# 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=true ;; #( CYGWIN* )
Darwin* ) darwin=true ;; #( cygwin=true
MSYS* | MINGW* ) msys=true ;; #( ;;
NONSTOP* ) nonstop=true ;; Darwin* )
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
@ -119,9 +87,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
@ -130,120 +98,88 @@ 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"
if ! command -v java >/dev/null 2>&1 which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
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" && ! "$darwin" && ! "$nonstop" ; then if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
case $MAX_FD in #( MAX_FD_LIMIT=`ulimit -H -n`
max*) if [ $? -eq 0 ] ; then
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
# shellcheck disable=SC2039,SC3045 MAX_FD="$MAX_FD_LIMIT"
MAX_FD=$( ulimit -H -n ) || fi
warn "Could not query maximum file descriptor limit" ulimit -n $MAX_FD
esac if [ $? -ne 0 ] ; then
case $MAX_FD in #( warn "Could not set maximum file descriptor limit: $MAX_FD"
'' | soft) :;; #( fi
*) else
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
# shellcheck disable=SC2039,SC3045 fi
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi fi
# Collect all arguments for the java command, stacking in reverse order: # For Darwin, add options to specify how the application appears in the dock
# * args from the command line if $darwin; then
# * the main class name GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
# * -classpath fi
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=$( cygpath --unix "$JAVACMD" ) JAVACMD=`cygpath --unix "$JAVACMD"`
# Now convert the arguments - kludge to limit ourselves to /bin/sh # We build the pattern for arguments to be converted via cygpath
for arg do ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
if SEP=""
case $arg in #( for dir in $ROOTDIRSRAW ; do
-*) false ;; # don't mess with options #( ROOTDIRS="$ROOTDIRS$SEP$dir"
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath SEP="|"
[ -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 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
fi fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Collect all arguments for the java command, following the shell quoting and substitution rules
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# 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" "$@"

11
gradlew.bat vendored
View File

@ -26,7 +26,6 @@ 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%
@ -41,7 +40,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% equ 0 goto execute if "%ERRORLEVEL%" == "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.
@ -76,15 +75,13 @@ 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% equ 0 goto mainEnd if "%ERRORLEVEL%"=="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!
set EXIT_CODE=%ERRORLEVEL% if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
if %EXIT_CODE% equ 0 set EXIT_CODE=1 exit /b 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("@webSecurity.isInGuild(#guildId)") @PreAuthorize("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("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId, #body)") @PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId, #body)")
public ResponseEntity<Status> connect(@PathVariable String guildId, @RequestBody Connect body, public ResponseEntity<Status> connect(@PathVariable String guildId, @RequestBody Connect body, Authentication authentication) {
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("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)") @PreAuthorize("isInGuild(#guildId) && 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("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)") @PreAuthorize("isInGuild(#guildId) && 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("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)") @PreAuthorize("isInGuild(#guildId) && 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("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)") @PreAuthorize("isInGuild(#guildId) && 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("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)") @PreAuthorize("isInGuild(#guildId) && 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("@webSecurity.isInGuild(#guildId) && @webSecurity.canInteractWithVoiceChannel(#guildId)") @PreAuthorize("isInGuild(#guildId) && canInteractWithVoiceChannel(#guildId)")
public ResponseEntity<Status> add(@PathVariable String guildId, @RequestBody Add body, public ResponseEntity<Status> add(@PathVariable String guildId, @RequestBody Add body, Authentication authentication) throws ExecutionException, InterruptedException {
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,8 +19,7 @@ public class AuthController {
private final JwtService jwtService; private final JwtService jwtService;
public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository, public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository, JwtService jwtService) {
JwtService jwtService) {
this.authenticationManager = authenticationManager; this.authenticationManager = authenticationManager;
this.jwtService = jwtService; this.jwtService = jwtService;
} }
@ -28,12 +27,14 @@ 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,6 +8,7 @@ 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)
@ -17,7 +18,10 @@ public class CrossOptionController {
/** /**
* For cross preflight request send by axios * For cross preflight request send by axios
*/ */
@RequestMapping(value = "/**", method = RequestMethod.OPTIONS) @RequestMapping(
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("@webSecurity.isInGuild(#guildId)") @PreAuthorize("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("@webSecurity.isInGuild(#guildId)") @PreAuthorize("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("@webSecurity.isInGuild(#guildId)") @PreAuthorize("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

@ -26,13 +26,13 @@ public class SettingController {
} }
@GetMapping("/{guildId}/values") @GetMapping("/{guildId}/values")
@PreAuthorize("@webSecurity.isInGuild(#guildId) && @webSecurity.canManageGuild(#guildId)") @PreAuthorize("isInGuild(#guildId) && 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("@webSecurity.isInGuild(#guildId) && @webSecurity.anManageGuild(#guildId)") @PreAuthorize("isInGuild(#guildId) && 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 jakarta.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
public record Login( public record Login(
@NotBlank String code, @NotBlank String redirectUri) { @NotBlank String code, @NotBlank String redirectUri) {

View File

@ -7,5 +7,6 @@ public record PlayBackInfo(
Boolean paused, Boolean paused,
Boolean stopped, Boolean stopped,
Long progress, Long progress,
TrackInfo trackInfo) { TrackInfo trackInfo
) {
} }

View File

@ -11,5 +11,6 @@ public record Status(
Channel channel, Channel channel,
Boolean canView, Boolean canView,
Boolean canInteract, Boolean canInteract,
PlayBackInfo playBackInfo) { PlayBackInfo playBackInfo
) {
} }

View File

@ -7,8 +7,7 @@ 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(), this(new UserInfo(userAudioTrack.getSubmittedUser().getId(), userAudioTrack.getSubmittedUser().getName(), userAudioTrack.getSubmittedUser().getAvatarUrl()),
userAudioTrack.getSubmittedUser().getAvatarUrl()),
userAudioTrack.getAudioTrack().getInfo()); userAudioTrack.getAudioTrack().getInfo());
} }
} }

View File

@ -7,7 +7,8 @@ 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

@ -8,5 +8,6 @@ import java.util.List;
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,12 +29,10 @@ 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 DiscordOauthService.LoginOrRegisterResponse<UserEntity> loginOrRegisterResponse = discordOauthService.loginOrRegisterDiscordUser(discordOauthUserInfo);
.loginOrRegisterDiscordUser(discordOauthUserInfo);
UserEntity userEntity = loginOrRegisterResponse.response(); UserEntity userEntity = loginOrRegisterResponse.response();
if(!loginOrRegisterResponse.created()){ if(!loginOrRegisterResponse.created()){
userEntity = discordOauthService.updateUserInfo(discordOauthUserInfo, userEntity = discordOauthService.updateUserInfo(discordOauthUserInfo, loginOrRegisterResponse.response());
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,17 +1,15 @@
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;
@ -21,9 +19,7 @@ public class UnauthorizedHandler implements AuthenticationEntryPoint {
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
@Override @Override
public void commence(HttpServletRequest request, public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
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

@ -9,3 +9,4 @@ public record DiscordOauthUserInfo(
String discriminator, String discriminator,
String avatar) { String avatar) {
} }

View File

@ -0,0 +1,25 @@
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

@ -0,0 +1,102 @@
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

@ -1,69 +0,0 @@
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,10 +2,6 @@ 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;
@ -19,6 +15,10 @@ 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,8 +32,7 @@ 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) protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
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 ", "");
@ -43,13 +42,13 @@ public class JwtFilter extends OncePerRequestFilter {
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.getPayload().getId(), user); principal = new JwtPrincipal(jwt.getBody().getId(), user);
} }
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(principal, null, new ArrayList<>());
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,47 +1,40 @@
package net.Broken.Api.Security; package net.Broken.Api.Security;
import static org.springframework.security.config.Customizer.withDefaults;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import net.Broken.Api.Security.Components.UnauthorizedHandler; import net.Broken.Api.Security.Components.UnauthorizedHandler;
import net.Broken.Api.Security.Filters.JwtFilter; import net.Broken.Api.Security.Filters.JwtFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity @EnableWebSecurity
@EnableMethodSecurity
@Configuration @Configuration
public class SecurityConfig { public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UnauthorizedHandler unauthorizedHandler; private final UnauthorizedHandler unauthorizedHandler;
public SecurityConfig(UnauthorizedHandler unauthorizedHandler) { public SecurityConfig(UnauthorizedHandler unauthorizedHandler) {
this.unauthorizedHandler = unauthorizedHandler; this.unauthorizedHandler = unauthorizedHandler;
} }
@Bean @Override
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.cors(withDefaults()).csrf(csrf -> csrf.disable()) http.cors().and().csrf().disable()
.exceptionHandling(handling -> handling.authenticationEntryPoint(unauthorizedHandler)) .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeHttpRequests(requests -> requests .authorizeRequests()
.requestMatchers("/api/v2/auth/**").permitAll() .antMatchers("/api/v2/auth/**").permitAll()
.requestMatchers("/api/v2/guild/inviteLink").permitAll() .antMatchers("/api/v2/guild/inviteLink").permitAll()
.requestMatchers("/swagger-ui/**").permitAll() .antMatchers("/swagger-ui/**").permitAll()
.requestMatchers("/swagger-ui.html").permitAll() .antMatchers("/swagger-ui.html").permitAll()
.requestMatchers("/v3/api-docs/**").permitAll() .antMatchers("/v3/api-docs/**").permitAll()
.requestMatchers("/actuator/**").permitAll() .antMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()); .anyRequest().authenticated();
http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class); http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
} }
@Bean @Bean
@ -49,9 +42,10 @@ public class SecurityConfig {
return new JwtFilter(); return new JwtFilter();
} }
@Bean @Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception { @Override
return http.getSharedObject(AuthenticationManagerBuilder.class) public AuthenticationManager authenticationManagerBean() throws Exception {
.build(); return super.authenticationManagerBean();
} }
} }

View File

@ -58,13 +58,11 @@ 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() logger.warn("[OAUTH] Invalid response while getting AccessToken: Status Code: " + response.statusCode() + " Body:" + response.body());
+ " Body:" + response.body());
throw new OAuthLoginFail(); throw new OAuthLoginFail();
} }
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
AccessTokenResponse accessTokenResponse = objectMapper.readValue(response.body(), AccessTokenResponse accessTokenResponse = objectMapper.readValue(response.body(), AccessTokenResponse.class);
AccessTokenResponse.class);
return accessTokenResponse.access_token(); return accessTokenResponse.access_token();
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
logger.catching(e); logger.catching(e);
@ -83,8 +81,7 @@ 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() logger.warn("[OAUTH] Invalid response while getting UserInfo: Status Code: " + response.statusCode() + " Body:" + response.body());
+ " Body:" + response.body());
throw new OAuthLoginFail(); throw new OAuthLoginFail();
} }
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
@ -102,14 +99,14 @@ 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() logger.warn("[OAUTH] Invalid response while token revocation: Status Code: " + response.statusCode() + " Body:" + response.body());
+ " 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) {
} }
@ -129,8 +126,7 @@ public class DiscordOauthService {
userEntity.setUsername(discordOauthUserInfo.username()); userEntity.setUsername(discordOauthUserInfo.username());
updated = true; updated = true;
} }
if (userEntity.getDiscriminator() == null if(userEntity.getDiscriminator() == null || !userEntity.getDiscriminator().equals(discordOauthUserInfo.discriminator())){
|| !userEntity.getDiscriminator().equals(discordOauthUserInfo.discriminator())) {
userEntity.setDiscriminator(discordOauthUserInfo.discriminator()); userEntity.setDiscriminator(discordOauthUserInfo.discriminator());
updated = true; updated = true;
} }
@ -145,6 +141,7 @@ public class DiscordOauthService {
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;
@ -160,8 +157,7 @@ public class DiscordOauthService {
return result.toString(); return result.toString();
} }
private HttpResponse<String> makeFormPost(String endpoint, HashMap<String, String> data) private HttpResponse<String> makeFormPost(String endpoint, HashMap<String, String> data) throws IOException, InterruptedException {
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))
@ -172,4 +168,5 @@ public class DiscordOauthService {
return client.send(request, HttpResponse.BodyHandlers.ofString()); return client.send(request, HttpResponse.BodyHandlers.ofString());
} }
} }

View File

@ -1,30 +1,31 @@
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 SecretKey jwtKey; private final Key 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 = Jwts.SIG.HS256.key().build(); this.jwtKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
} }
public String buildJwt(UserEntity user){ public String buildJwt(UserEntity user){
@ -35,29 +36,33 @@ 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()
.subject(user.getUsername()) .setSubject(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())
.id(uuid.toString()) .setId(uuid.toString())
.issuedAt(iat) .setIssuedAt(iat)
.notBefore(nbf) .setNotBefore(nbf)
.expiration(exp) .setExpiration(exp)
.signWith(this.jwtKey) .signWith(this.jwtKey)
.compact(); .compact();
} }
public Jws<Claims> verifyAndParseJwt(String token) { public Jws<Claims> verifyAndParseJwt(String token) {
return Jwts.parser() return Jwts.parserBuilder()
.verifyWith(this.jwtKey) .setSigningKey(this.jwtKey)
.build() .build()
.parseSignedClaims(token); .parseClaimsJws(token);
} }
public UserEntity getUserWithJwt(Jws<Claims> jwt) throws NoSuchElementException { public UserEntity getUserWithJwt(Jws<Claims> jwt) throws NoSuchElementException {
String discordId = jwt.getPayload().get("discord_id", String.class); String discordId = jwt.getBody().get("discord_id", String.class);
return userRepository.findByDiscordId(discordId) return userRepository.findByDiscordId(discordId)
.orElseThrow(); .orElseThrow();
} }

View File

@ -9,9 +9,7 @@ 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.channel.concrete.VoiceChannel; import net.dv8tion.jda.api.entities.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;
@ -29,13 +27,13 @@ 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 // -> OR He can *not* view the voice channel, but he is connected to this voice channel
// 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);
@ -51,13 +49,13 @@ public class AudioService {
&& 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 UserAudioTrack userAudioTrack = guildAudioBotService.getGuidAudioManager().scheduler.getCurrentPlayingTrack();
.getCurrentPlayingTrack();
playBackInfo = new PlayBackInfo(paused, false, position, new TrackInfo(userAudioTrack)); playBackInfo = new PlayBackInfo(paused, false, position, new TrackInfo(userAudioTrack));
@ -90,6 +88,7 @@ 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();
@ -118,8 +117,7 @@ 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) public ResponseEntity<Status> add(String guildId, String userId, Add body) throws ExecutionException, InterruptedException {
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,9 +8,6 @@ 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;
@ -27,7 +24,8 @@ 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;
@ -37,7 +35,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 (VoiceChannel voiceChannel : guild.getVoiceChannels()) { for (net.dv8tion.jda.api.entities.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()));
} }
@ -49,7 +47,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 (TextChannel textChannel : guild.getTextChannels()) { for (net.dv8tion.jda.api.entities.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()));
} }
@ -68,9 +66,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,6 +19,7 @@ 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;
} }
@ -27,6 +28,7 @@ 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");

View File

@ -1,17 +1,14 @@
package net.Broken.Audio; package net.Broken.Audio;
import java.nio.ByteBuffer;
import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; import com.sedmelluq.discord.lavaplayer.player.AudioPlayer;
import com.sedmelluq.discord.lavaplayer.track.playback.MutableAudioFrame; import com.sedmelluq.discord.lavaplayer.track.playback.MutableAudioFrame;
import net.dv8tion.jda.api.audio.AudioSendHandler; import net.dv8tion.jda.api.audio.AudioSendHandler;
import java.nio.ByteBuffer;
/** /**
* This is a wrapper around AudioPlayer which makes it behave as an * This is a wrapper around AudioPlayer which makes it behave as an AudioSendHandler for JDA. As JDA calls canProvide
* 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
* 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,19 +24,17 @@ 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.channel.middleman.AudioChannel; import net.dv8tion.jda.api.entities.VoiceChannel;
import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion; import net.dv8tion.jda.api.events.interaction.GenericInteractionCreateEvent;
import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
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.buttons.Button; import net.dv8tion.jda.api.interactions.components.Button;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
public class GuildAudioBotService { public class GuildAudioBotService {
@ -49,7 +47,7 @@ public class GuildAudioBotService {
/** /**
* Extrem limit for playlist * Extrem limit for playlist
*/ */
private static final int LIST_EXTREM_LIMIT = 300; private final int listExtremLimit = 300;
private final Guild guild; private final Guild guild;
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
@ -68,7 +66,9 @@ public class GuildAudioBotService {
} }
public static GuildAudioBotService getInstance(Guild guild) { public static GuildAudioBotService getInstance(Guild guild) {
INSTANCES.computeIfAbsent(guild, k -> new GuildAudioBotService(guild)); if (!INSTANCES.containsKey(guild)) {
INSTANCES.put(guild, new GuildAudioBotService(guild));
}
return INSTANCES.get(guild); return INSTANCES.get(guild);
} }
@ -80,14 +80,13 @@ 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(SlashCommandInteractionEvent event, AudioChannel voiceChannel, final String trackUrl, public void loadAndPlay(SlashCommandEvent event, VoiceChannel voiceChannel, final String trackUrl, int playlistLimit, boolean onHead) {
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("[{}] Single Track detected!", guild.getName()); logger.info("[" + guild + "] Single Track detected!");
UserAudioTrack uat = new UserAudioTrack(event.getUser(), track); UserAudioTrack uat = new UserAudioTrack(event.getUser(), track);
MessageCreateData message = new MessageCreateBuilder() Message message = new MessageBuilder()
.setEmbeds(EmbedMessageUtils.getMusicAdded(track.getInfo(), event.getMember(), -1)) .setEmbeds(EmbedMessageUtils.getMusicAdded(track.getInfo(), event.getMember(), -1))
.build(); .build();
clearLastButton(); clearLastButton();
@ -97,10 +96,10 @@ public class GuildAudioBotService {
@Override @Override
public void playlistLoaded(AudioPlaylist playlist) { public void playlistLoaded(AudioPlaylist playlist) {
logger.info("[{}] Playlist detected! Limit: {}", guild, playlistLimit); logger.info("[" + guild + "] Playlist detected! Limit: " + 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);
MessageCreateData message = new MessageCreateBuilder() Message message = new MessageBuilder()
.setEmbeds(EmbedMessageUtils.getMusicAdded(firstTrack.getInfo(), event.getMember(), size)) .setEmbeds(EmbedMessageUtils.getMusicAdded(firstTrack.getInfo(), event.getMember(), size))
.build(); .build();
clearLastButton(); clearLastButton();
@ -110,18 +109,16 @@ public class GuildAudioBotService {
@Override @Override
public void noMatches() { public void noMatches() {
logger.warn("[{}] Cant find media!", guild); logger.warn("[" + guild + "] Cant find media!");
MessageCreateData message = new MessageCreateBuilder() Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Video not found !")).build();
.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("[{}] Can't load media!", guild); logger.error("[" + guild + "] Can't load media!");
logger.error(exception.getMessage()); logger.error(exception.getMessage());
MessageCreateData message = new MessageCreateBuilder() Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Playback error !")).build();
.setEmbeds(EmbedMessageUtils.getMusicError("Playback error !")).build();
event.getHook().setEphemeral(true).sendMessage(message).queue(); event.getHook().setEphemeral(true).sendMessage(message).queue();
} }
}); });
@ -129,13 +126,12 @@ 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);
AudioChannelUnion playedChanel = guild.getAudioManager().getConnectedChannel(); VoiceChannel playedChanel = guild.getAudioManager().getConnectedChannel();
final String uuid = UUID.randomUUID().toString(); final String uuid = UUID.randomUUID().toString();
Future<Void> future = audioPlayerManager.loadItemOrdered(guildAudioManager, trackUrl, Future<Void> future = audioPlayerManager.loadItemOrdered(guildAudioManager, trackUrl, new AudioLoadResultHandler() {
new AudioLoadResultHandler() {
@Override @Override
public void trackLoaded(AudioTrack track) { public void trackLoaded(AudioTrack track) {
logger.info("[{}] Auto add {} to playlist.", guild, track.getInfo().title); logger.info("[" + guild + "] Auto add " + track.getInfo().title + " to playlist.");
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);
@ -144,7 +140,7 @@ public class GuildAudioBotService {
@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("[{}] Auto add {} to playlist.", guild, track.getInfo().title); logger.info("[" + guild + "] Auto add " + track.getInfo().title + " to playlist.");
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);
@ -152,13 +148,13 @@ public class GuildAudioBotService {
@Override @Override
public void noMatches() { public void noMatches() {
logger.warn("[{}] Track not found: {}", guild, trackUrl); logger.warn("[" + guild + "] Track not found: " + trackUrl);
addStatus.put(uuid, false); addStatus.put(uuid, false);
} }
@Override @Override
public void loadFailed(FriendlyException exception) { public void loadFailed(FriendlyException exception) {
logger.error("[{}] Cant load media!", guild); logger.error("[" + guild + "] Cant load media!");
logger.error(exception.getMessage()); logger.error(exception.getMessage());
addStatus.put(uuid, false); addStatus.put(uuid, false);
} }
@ -167,6 +163,7 @@ public class GuildAudioBotService {
return addStatus.remove(uuid); return addStatus.remove(uuid);
} }
/** /**
* Load playlist to playlist * Load playlist to playlist
* *
@ -177,7 +174,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) {
AudioChannelUnion playedChanel = guild.getAudioManager().getConnectedChannel(); VoiceChannel playedChanel = guild.getAudioManager().getConnectedChannel();
List<AudioTrack> tracks = playlist.getTracks(); List<AudioTrack> tracks = playlist.getTracks();
if (onHead) if (onHead)
Collections.reverse(tracks); Collections.reverse(tracks);
@ -186,12 +183,13 @@ 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 > LIST_EXTREM_LIMIT) if ((playlistLimit != -1 && i >= playlistLimit) || i > listExtremLimit)
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
* *
@ -201,8 +199,7 @@ 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, AudioChannel channel, GuildAudioManager musicManager, UserAudioTrack track, public void play(Guild guild, VoiceChannel channel, GuildAudioManager musicManager, UserAudioTrack track, boolean onHead) {
boolean onHead) {
if (!guild.getAudioManager().isConnected()) if (!guild.getAudioManager().isConnected())
guild.getAudioManager().openAudioConnection(channel); guild.getAudioManager().openAudioConnection(channel);
if (!onHead) if (!onHead)
@ -211,88 +208,87 @@ public class GuildAudioBotService {
musicManager.scheduler.addNext(track); musicManager.scheduler.addNext(track);
} }
public void add(SlashCommandInteractionEvent event, String url, int playListLimit, boolean onHead) { public void add(SlashCommandEvent 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 {
MessageCreateData message = new MessageCreateBuilder() Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("Not connected to vocal chanel !")).build();
.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(AudioChannel voiceChannel) { public void connect(VoiceChannel voiceChannel) {
guild.getAudioManager().openAudioConnection(voiceChannel); guild.getAudioManager().openAudioConnection(voiceChannel);
} }
public void pause(InteractionHook hook) { public void pause(GenericInteractionCreateEvent event) {
pause(); pause();
MessageCreateData message = new MessageCreateBuilder().setEmbeds( Message message = new MessageBuilder().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 = hook.sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
} }
public void pause() { public void pause() {
guildAudioManager.scheduler.pause(); guildAudioManager.scheduler.pause();
} }
public void resume(InteractionHook hook) { public void resume(GenericInteractionCreateEvent event) {
MessageCreateData message; Message message;
if (guildAudioManager.player.getPlayingTrack() == null) { if (guildAudioManager.player.getPlayingTrack() == null) {
message = new MessageCreateBuilder().setEmbeds( message = new MessageBuilder().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 MessageCreateBuilder().setEmbeds( message = new MessageBuilder().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 = hook.sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
} }
public void resume() { public void resume() {
guildAudioManager.scheduler.resume(); guildAudioManager.scheduler.resume();
} }
public void skipTrack(InteractionHook hook) { public void skipTrack(GenericInteractionCreateEvent event) {
skipTrack(); skipTrack();
MessageCreateData message = new MessageCreateBuilder().setEmbeds( Message message = new MessageBuilder().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 = hook.sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
} }
public void skipTrack() { public void skipTrack() {
guildAudioManager.scheduler.nextTrack(); guildAudioManager.scheduler.nextTrack();
} }
public void stop(InteractionHook hook) { public void stop(GenericInteractionCreateEvent event) {
stop(); stop();
MessageCreateData message = new MessageCreateBuilder().setEmbeds( Message message = new MessageBuilder().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 = hook.sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
} }
@ -302,16 +298,16 @@ public class GuildAudioBotService {
clearLastButton(); clearLastButton();
} }
public void disconnect(InteractionHook hook) { public void disconnect(GenericInteractionCreateEvent event) {
disconnect(); disconnect();
MessageCreateData message = new MessageCreateBuilder().setEmbeds( Message message = new MessageBuilder().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();
hook.sendMessage(message).queue(); event.getHook().sendMessage(message).queue();
} }
public void disconnect() { public void disconnect() {
@ -320,26 +316,24 @@ 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();
MessageCreateData message = new MessageCreateBuilder() Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicInfo(info, userAudioTrack)).build();
.setEmbeds(EmbedMessageUtils.getMusicInfo(info, userAudioTrack)).build();
clearLastButton(); clearLastButton();
lastMessageWithButton = hook.sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
} }
public void flush(InteractionHook hook) { public void flush(GenericInteractionCreateEvent event) {
guildAudioManager.scheduler.flush(); guildAudioManager.scheduler.flush();
MessageCreateData message = new MessageCreateBuilder().setEmbeds( Message message = new MessageBuilder().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 = hook.sendMessage(message).addActionRow(getActionButton()).complete(); lastMessageWithButton = event.getHook().sendMessage(message).addActionRow(getActionButton()).complete();
} }
/** /**
@ -347,18 +341,18 @@ public class GuildAudioBotService {
* *
* @param event * @param event
*/ */
public void list(InteractionHook hook) { public void list(GenericInteractionCreateEvent event) {
List<UserAudioTrack> list = guildAudioManager.scheduler.getList(); List<UserAudioTrack> list = guildAudioManager.scheduler.getList();
if (list.isEmpty()) { if (list.size() == 0) {
MessageCreateData message = new MessageCreateBuilder().setEmbeds( Message message = new MessageBuilder().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();
hook.sendMessage(message).queue(); event.getHook().sendMessage(message).queue();
} else { } else {
StringBuilder resp = new StringBuilder(); StringBuilder resp = new StringBuilder();
int i = 0; int i = 0;
@ -376,14 +370,14 @@ public class GuildAudioBotService {
} }
i++; i++;
} }
MessageCreateData message = new MessageCreateBuilder().setEmbeds( Message message = new MessageBuilder().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();
hook.sendMessage(message).queue(); event.getHook().sendMessage(message).queue();
} }
} }
@ -396,6 +390,7 @@ 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();
@ -406,10 +401,10 @@ public class GuildAudioBotService {
public void updateLastButton() { public void updateLastButton() {
if (lastMessageWithButton != null) if (lastMessageWithButton != null)
lastMessageWithButton = lastMessageWithButton.editMessageComponents(ActionRow.of(getActionButton())) lastMessageWithButton = lastMessageWithButton.editMessageComponents(ActionRow.of(getActionButton())).complete();
.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,8 +19,7 @@ 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 * This class schedules tracks for the audio player. It contains the queue of tracks.
* tracks.
*/ */
public class TrackScheduler extends AudioEventAdapter { public class TrackScheduler extends AudioEventAdapter {
private final AudioPlayer player; private final AudioPlayer player;
@ -47,10 +46,8 @@ 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 // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If
// 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
// 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");
@ -69,10 +66,8 @@ 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 // Calling startTrack with the noInterrupt set to true will start the track only if nothing is currently playing. If
// 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
// 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);
@ -139,10 +134,8 @@ 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. // Start the next track, regardless of if something is already playing or not. In case queue was empty, we are
// In case queue was empty, we are // giving null to startTrack, which is a valid argument and will simply stop the player.
// 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;
@ -152,8 +145,7 @@ 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 // Only start the next track if the end reason is suitable for it (FINISHED or LOAD_FAILED)
// 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.");
@ -163,6 +155,7 @@ public class TrackScheduler extends AudioEventAdapter {
nextTrack(); nextTrack();
} }
} }
} }

View File

@ -1,11 +1,13 @@
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,13 +1,5 @@
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;
@ -15,21 +7,28 @@ 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.entities.Guild; import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.events.ReadyEvent;
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.GuildVoiceUpdateEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceJoinEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMoveEvent;
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 net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import org.apache.logging.log4j.LogManager;
import net.dv8tion.jda.api.utils.messages.MessageCreateData; import org.apache.logging.log4j.Logger;
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
@ -51,27 +50,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("[{}] : {} join the guild, adding default role !", event.getGuild().getName(), logger.info("[" + event.getGuild().getName() + "] : " + event.getUser().getName() + " join the guild, adding default role !");
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) { event.getGuild().addRoleToMember(event.getMember(), default_role).queue();
event.getGuild().addRoleToMember(event.getMember(), defaultRole).queue();
} else { } else {
logger.fatal("[{}] : Default role is null !", event.getGuild().getName()); logger.fatal("[" + event.getGuild().getName() + "] : Default role is null !");
} }
} }
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().replace("@name", event.getMember().getAsMention()); String message = guildPref.getWelcomeMessage().replaceAll("@name", event.getMember().getAsMention());
logger.debug(message); logger.debug(message);
chanel.sendMessage(message).queue(); chanel.sendMessage(message).queue();
} else { } else {
logger.fatal("[{}] : Welcome chanel is null !", event.getGuild().getName()); logger.fatal("[" + event.getGuild().getName() + "] : Welcome chanel is null !");
} }
} }
@ -80,24 +79,41 @@ 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() && event.getMember().getRoles().isEmpty()) { if (guildPref.isDefaultRole()) {
logger.info("[{}] : {} have no roles, reset to default !", event.getGuild().getName(), if (event.getMember().getRoles().size() == 0) {
event.getUser().getName()); logger.info("[" + event.getGuild().getName() + "] : " + event.getUser().getName() + " have no roles, reset to default !");
Role defaultRole = event.getGuild().getRoleById(guildPref.getDefaultRoleId()); Role default_role = event.getGuild().getRoleById(guildPref.getDefaultRoleId());
if (defaultRole == null) { if (default_role == null) {
logger.fatal("[{}] : Default role is null !", event.getGuild().getName()); logger.fatal("[" + event.getGuild().getName() + "] : Default role is null !");
return; return;
} }
event.getGuild().addRoleToMember(event.getMember(), defaultRole).queue(); event.getGuild().addRoleToMember(event.getMember(), default_role).queue();
}
} }
}
@Override
public void onGuildVoiceJoin(GuildVoiceJoinEvent event) {
super.onGuildVoiceJoin(event);
if (!event.getMember().getUser().isBot()) {
UserStatsUtils userStatsUtils = UserStatsUtils.getINSTANCE();
if (!userStatsUtils.runningCounters.containsKey(event.getMember().getId())) {
UserStatsUtils.VoicePresenceCounter temp = new UserStatsUtils.VoicePresenceCounter(event.getMember());
temp.start();
userStatsUtils.runningCounters.put(event.getMember().getId(), temp);
}
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.join(event.getChannelJoined());
}
} }
@Override @Override
public void onGuildVoiceUpdate(GuildVoiceUpdateEvent event) { public void onGuildVoiceLeave(GuildVoiceLeaveEvent event) {
super.onGuildVoiceUpdate(event); super.onGuildVoiceLeave(event);
// Disconnect
if (event.getChannelJoined() == null) {
if (event.getGuild().getAudioManager().isConnected()) { if (event.getGuild().getAudioManager().isConnected()) {
logger.trace("User disconnected from voice channel."); logger.trace("User disconnected from voice channel.");
@ -111,25 +127,14 @@ public class BotListener extends ListenerAdapter {
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild()); AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.leave(event.getChannelLeft()); autoVoiceChannel.leave(event.getChannelLeft());
} }
// Connect
else if (event.getChannelLeft() == null && !event.getMember().getUser().isBot()) { @Override
UserStatsUtils userStatsUtils = UserStatsUtils.getINSTANCE(); public void onGuildVoiceMove(@NotNull GuildVoiceMoveEvent event) {
if (!userStatsUtils.runningCounters.containsKey(event.getMember().getId())) { super.onGuildVoiceMove(event);
UserStatsUtils.VoicePresenceCounter temp = new UserStatsUtils.VoicePresenceCounter(
event.getMember());
temp.start();
userStatsUtils.runningCounters.put(event.getMember().getId(), temp);
}
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.join(event.getChannelJoined());
}
// Move
else {
AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild()); AutoVoiceChannel autoVoiceChannel = AutoVoiceChannel.getInstance(event.getGuild());
autoVoiceChannel.leave(event.getChannelLeft()); autoVoiceChannel.leave(event.getChannelLeft());
autoVoiceChannel.join(event.getChannelJoined()); autoVoiceChannel.join(event.getChannelJoined());
} }
}
@Override @Override
public void onMessageReceived(MessageReceivedEvent event) { public void onMessageReceived(MessageReceivedEvent event) {
@ -139,23 +144,23 @@ public class BotListener extends ListenerAdapter {
} }
@Override @Override
public void onButtonInteraction(ButtonInteractionEvent event) { public void onButtonClick(@NotNull ButtonClickEvent event) {
super.onButtonInteraction(event); super.onButtonClick(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.getHook()); case "pause" -> guildAudioBotService.pause(event);
case "play" -> guildAudioBotService.resume(event.getHook()); case "play" -> guildAudioBotService.resume(event);
case "next" -> guildAudioBotService.skipTrack(event.getHook()); case "next" -> guildAudioBotService.skipTrack(event);
case "stop" -> guildAudioBotService.stop(event.getHook()); case "stop" -> guildAudioBotService.stop(event);
case "disconnect" -> guildAudioBotService.disconnect(event.getHook()); case "disconnect" -> guildAudioBotService.disconnect(event);
} }
} }
@Override @Override
public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { public void onSlashCommand(@NotNull SlashCommandEvent 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
@ -165,16 +170,18 @@ 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.getChannel().asTextChannel().isNSFW()) { if (!commandRunner.isNSFW() || event.getTextChannel().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();
} }
} }
@ -183,23 +190,19 @@ public class BotListener extends ListenerAdapter {
@Override @Override
public void onGuildJoin(GuildJoinEvent event) { public void onGuildJoin(GuildJoinEvent event) {
logger.info("Join new guild! ({} {} Members)", event.getGuild().getName(), logger.info("Join new guild! (" + event.getGuild().getName() + " " + event.getGuild().getMembers().size() + " Members)");
event.getGuild().getMembers().size());
super.onGuildJoin(event); super.onGuildJoin(event);
getPreference(event.getGuild()); getPreference(event.getGuild());
event.getGuild().loadMembers() event.getGuild().loadMembers().onSuccess((members -> logger.debug("[" + event.getGuild().getName() + "] Members loaded")));
.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( .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" +
"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()) "\nYou can access to my web UI with: " + botConfig.url())
.setImage("https://i.imgur.com/Anf1Srg.gif"); .setImage("https://i.imgur.com/Anf1Srg.gif");
MessageCreateData message = new MessageCreateBuilder().setEmbeds(EmbedMessageUtils.buildStandar(eb)).build(); Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.buildStandar(eb)).build();
TextChannel defaultChan = event.getGuild().getDefaultChannel().asTextChannel(); TextChannel defaultChan = event.getGuild().getDefaultChannel();
if (defaultChan.canTalk()) { if (defaultChan != null && defaultChan.canTalk()) {
defaultChan.sendMessage(message).queue(); defaultChan.sendMessage(message).queue();
} else { } else {
for (TextChannel chan : event.getGuild().getTextChannels()) { for (TextChannel chan : event.getGuild().getTextChannels()) {
@ -214,10 +217,12 @@ 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("[{}] : Generate default pref", guild.getName()); logger.info("[" + guild.getName() + "] : Generate default pref");
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,5 +1,6 @@
package net.Broken; package net.Broken;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
/** /**
@ -42,4 +43,5 @@ public interface Commande {
*/ */
boolean isNSFW(); boolean isNSFW();
} }

View File

@ -0,0 +1,132 @@
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

@ -0,0 +1,39 @@
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

@ -0,0 +1,69 @@
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,10 +1,6 @@
package net.Broken.DB.Entity; package net.Broken.DB.Entity;
import jakarta.persistence.Column; import javax.persistence.*;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity @Entity
public class GuildPreferenceEntity { public class GuildPreferenceEntity {
@ -31,6 +27,7 @@ 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,
@ -56,9 +53,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, return new GuildPreferenceEntity(guildId, false, "Welcome to this awesome server @name! ", null, false, null, true, false, null, null);
true, false, null, null);
} }
public Integer getId() { public Integer getId() {

View File

@ -1,19 +1,12 @@
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.
*/ */
@ -58,6 +51,7 @@ public class UserEntity {
this.avatar = discordOauthUserInfo.avatar(); this.avatar = discordOauthUserInfo.avatar();
} }
public Integer getId() { public Integer getId() {
return id; return id;
} }

View File

@ -2,12 +2,7 @@ package net.Broken.DB.Entity;
import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnDefault;
import jakarta.persistence.Entity; import javax.persistence.*;
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 {
@ -16,6 +11,7 @@ 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,10 +1,9 @@
package net.Broken.DB.Repository; package net.Broken.DB.Repository;
import java.util.Optional; import net.Broken.DB.Entity.GuildPreferenceEntity;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import net.Broken.DB.Entity.GuildPreferenceEntity; import java.util.Optional;
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,10 +1,13 @@
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;
@ -16,12 +19,14 @@ 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) {
@ -42,18 +47,19 @@ 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 {} Guilds:", jda.getGuilds().size()); logger.info("Connected on " + jda.getGuilds().size() + " Guilds:");
for (Guild server : jda.getGuilds()) { for (Guild server : jda.getGuilds()) {
server.loadMembers(); server.loadMembers();
} }
return jda; return jda;
} catch (InterruptedException e) { } catch (LoginException | 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();
@ -69,10 +75,20 @@ 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()){
@ -107,5 +123,6 @@ public class Init {
} }
} }
} }
} }

View File

@ -10,7 +10,6 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean; 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 org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import java.util.HashMap; import java.util.HashMap;
@ -29,6 +28,7 @@ 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,7 +56,8 @@ public class MainBot {
@Bean @Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() { public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer propsConfig = new PropertySourcesPlaceholderConfigurer(); PropertySourcesPlaceholderConfigurer propsConfig
= 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,7 +1,6 @@
package net.Broken; package net.Broken;
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.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;
@ -11,7 +10,7 @@ import java.util.List;
* Interface that define command structure. * Interface that define command structure.
*/ */
public interface SlashCommand { public interface SlashCommand {
void action(SlashCommandInteractionEvent event); void action(SlashCommandEvent event);
String getDescription(); String getDescription();
@ -35,5 +34,7 @@ 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,12 +17,10 @@ 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.Permission; import net.dv8tion.jda.api.MessageBuilder;
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.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.
@ -31,34 +29,32 @@ public class Cat implements SlashCommand {
private final Logger logger = LogManager.getLogger(); private final Logger logger = LogManager.getLogger();
@Override @Override
public void action(SlashCommandInteractionEvent event) { public void action(SlashCommandEvent 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: {} Body: {}", response.statusCode(), logger.warn("[CAT] Fail to fetch cat: Status Code: " + response.statusCode() + " Body:" + response.body());
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 MessageCreateBuilder().setEmbeds(EmbedMessageUtils.getInternalError()).build()) event.reply(new MessageBuilder().setEmbeds(EmbedMessageUtils.getInternalError()).build()).setEphemeral(true).queue();
.setEphemeral(true)
.queue();
} }
} }
@Override @Override
@ -68,14 +64,15 @@ public class Cat implements SlashCommand {
@Override @Override
public List<OptionData> getOptions() { public List<OptionData> getOptions() {
return Collections.emptyList(); return null;
} }
@Override @Override
public List<SubcommandData> getSubcommands() { public List<SubcommandData> getSubcommands() {
return Collections.emptyList(); return null;
} }
/** /**
* Determines if the command is usable only by bot level admin user * Determines if the command is usable only by bot level admin user
* *
@ -97,8 +94,7 @@ public class Cat implements SlashCommand {
} }
@Override @Override
public DefaultMemberPermissions getDefaultPermissions() { public boolean isDisableByDefault() {
return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND); return false;
} }
} }

View File

@ -1,33 +1,29 @@
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.channel.middleman.MessageChannel; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
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 net.dv8tion.jda.api.utils.messages.MessageCreateData; import java.util.ArrayList;
import java.util.List;
public class Clear implements SlashCommand { public class Clear implements SlashCommand {
@Override @Override
public void action(SlashCommandInteractionEvent event) { public void action(SlashCommandEvent 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 {
MessageCreateData message = new MessageCreateBuilder() Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getFlushError("You are not a supreme being, you cannot do that !")).build();
.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();
} }
} }
@ -46,7 +42,7 @@ public class Clear implements SlashCommand {
@Override @Override
public List<SubcommandData> getSubcommands() { public List<SubcommandData> getSubcommands() {
return Collections.emptyList(); return null;
} }
@Override @Override
@ -65,8 +61,7 @@ public class Clear implements SlashCommand {
} }
@Override @Override
public DefaultMemberPermissions getDefaultPermissions() { public boolean isDisableByDefault() {
return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_MANAGE); return true;
} }
} }

View File

@ -1,52 +1,48 @@
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.SlashCommand;
import net.Broken.Audio.GuildAudioBotService; import net.Broken.Audio.GuildAudioBotService;
import net.Broken.SlashCommand;
import net.Broken.Tools.EmbedMessageUtils; import net.Broken.Tools.EmbedMessageUtils;
import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion; import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.entities.VoiceChannel;
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 net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import org.apache.logging.log4j.LogManager;
import net.dv8tion.jda.api.utils.messages.MessageCreateData; import org.apache.logging.log4j.Logger;
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(SlashCommandInteractionEvent event) { public void action(SlashCommandEvent 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().inAudioChannel()) { if (event.getMember().getVoiceState().inVoiceChannel()) {
AudioChannelUnion voiceChanel = event.getMember().getVoiceState().getChannel(); VoiceChannel 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 {
MessageCreateData message = new MessageCreateBuilder() Message message = new MessageBuilder().setEmbeds(EmbedMessageUtils.getMusicError("You are not in a voice channel !")).build();
.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;
@ -56,34 +52,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.getHook()); audio.pause(event);
break; break;
case "resume": case "resume":
audio.resume(event.getHook()); audio.resume(event);
break; break;
case "next": case "next":
audio.skipTrack(event.getHook()); audio.skipTrack(event);
break; break;
case "stop": case "stop":
case "disconnect": case "disconnect":
audio.stop(event.getHook()); audio.stop(event);
break; break;
case "info": case "info":
audio.info(event.getHook()); audio.info(event);
break; break;
case "flush": case "flush":
audio.flush(event.getHook()); audio.flush(event);
break; break;
case "list": case "list":
audio.list(event.getHook()); audio.list(event);
break; break;
} }
} }
@ -95,7 +91,7 @@ public class Music implements SlashCommand {
@Override @Override
public List<OptionData> getOptions() { public List<OptionData> getOptions() {
return Collections.emptyList(); return null;
} }
@Override @Override
@ -103,14 +99,11 @@ 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, .addOption(OptionType.INTEGER, "playlist-limit", "If a playlist is loaded, enter the max number of loaded tracks (default to 30)"));
"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", .addOption(OptionType.BOOLEAN, "next", "If true, track will be added on top of the playlist and will be the next to play")
"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)"));
.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"));
@ -121,6 +114,7 @@ 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
* *
@ -142,8 +136,7 @@ public class Music implements SlashCommand {
} }
@Override @Override
public DefaultMemberPermissions getDefaultPermissions() { public boolean isDisableByDefault() {
return DefaultMemberPermissions.ENABLED; return false;
} }
} }

View File

@ -1,12 +1,9 @@
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 net.dv8tion.jda.api.Permission; import org.apache.logging.log4j.LogManager;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
@NoDev @NoDev
@Ignore @Ignore
@ -16,6 +13,7 @@ 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";
@ -37,7 +35,7 @@ public class Ass extends NumberedSlashCommand {
} }
@Override @Override
public DefaultMemberPermissions getDefaultPermissions() { public boolean isDisableByDefault() {
return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND); return true;
} }
} }

View File

@ -3,9 +3,6 @@ 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;
@ -18,6 +15,7 @@ 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";
@ -39,7 +37,7 @@ public class Boobs extends NumberedSlashCommand {
} }
@Override @Override
public DefaultMemberPermissions getDefaultPermissions() { public boolean isDisableByDefault() {
return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND); return true;
} }
} }

View File

@ -2,8 +2,6 @@ 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;
@ -17,7 +15,6 @@ 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
* *
@ -26,8 +23,7 @@ public class Madame extends NumberedSlashCommand {
* @throws StringIndexOutOfBoundsException * @throws StringIndexOutOfBoundsException
* @throws IOException * @throws IOException
*/ */
private boolean scanPageForTipeee(String url, Logger logger) private boolean scanPageForTipeee(String url, Logger logger) throws StringIndexOutOfBoundsException, IOException, InterruptedException {
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"));
@ -50,6 +46,7 @@ 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;
@ -60,10 +57,11 @@ 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");
@ -96,7 +94,7 @@ public class Madame extends NumberedSlashCommand {
} }
@Override @Override
public DefaultMemberPermissions getDefaultPermissions() { public boolean isDisableByDefault() {
return DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND); return true;
} }
} }

View File

@ -1,28 +1,27 @@
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.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.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.buttons.Button; import net.dv8tion.jda.api.interactions.components.Button;
import java.util.List;
public class Rank implements SlashCommand { public class Rank implements SlashCommand {
@Override @Override
public void action(SlashCommandInteractionEvent event) { public void action(SlashCommandEvent 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")).queue(); Button.link("https://" + url + "/rank", "More stats")
).queue();
} }
@Override @Override
@ -32,12 +31,12 @@ public class Rank implements SlashCommand {
@Override @Override
public List<OptionData> getOptions() { public List<OptionData> getOptions() {
return Collections.emptyList(); return null;
} }
@Override @Override
public List<SubcommandData> getSubcommands() { public List<SubcommandData> getSubcommands() {
return Collections.emptyList(); return null;
} }
@Override @Override
@ -56,7 +55,7 @@ public class Rank implements SlashCommand {
} }
@Override @Override
public DefaultMemberPermissions getDefaultPermissions() { public boolean isDisableByDefault() {
return DefaultMemberPermissions.ENABLED; return false;
} }
} }

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 org.apache.logging.log4j.LogManager; import static net.Broken.MainBot.jda;
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,14 +34,14 @@ public class AutoVoiceChannel {
return INSTANCE_MAP.get(guild.getId()); return INSTANCE_MAP.get(guild.getId());
} }
public void join(AudioChannel voiceChannel) { public void join(VoiceChannel 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());
AudioChannel newChannel = (AudioChannel) voiceChannel.createCopy().complete(); 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()) {
@ -56,7 +56,7 @@ public class AutoVoiceChannel {
} }
public void leave(AudioChannel voiceChannel) { public void leave(VoiceChannel 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 +79,7 @@ public class AutoVoiceChannel {
return 999; return 999;
} }
private void moveMembers(List<Member> members, AudioChannel destination) { private void moveMembers(List<Member> members, VoiceChannel 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,11 @@
package net.Broken.Tools.Command; package net.Broken.Tools.Command;
import java.util.ArrayList; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import java.util.Arrays;
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 net.dv8tion.jda.api.events.message.MessageReceivedEvent; import java.util.ArrayList;
import java.util.Arrays;
/** /**
* *
@ -39,7 +38,8 @@ 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,8 +56,7 @@ 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, public CommandContainer(String brut, String sansTete, String[] splitSansTete, String commande, String[] args, MessageReceivedEvent e) {
MessageReceivedEvent e) {
this.brut = brut; this.brut = brut;
this.sansTete = sansTete; this.sansTete = sansTete;
this.splitSansTete = splitSansTete; this.splitSansTete = splitSansTete;

View File

@ -1,7 +1,6 @@
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;
@ -14,13 +13,12 @@ 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.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.interaction.SlashCommandEvent;
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 * Abstact class used for all command that need to find the max number of page on a web site.
* on a web site.
*/ */
@Ignore @Ignore
public abstract class NumberedSlashCommand implements SlashCommand { public abstract class NumberedSlashCommand implements SlashCommand {
@ -41,7 +39,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)
*/ */
protected NumberedSlashCommand(Logger logger, String baseURL, String urlSuffix, String divClass, String htmlType) { public 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;
@ -50,19 +48,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);
} }
} }
protected NumberedSlashCommand(Logger logger, String baseURL, String urlSuffix) { public NumberedSlashCommand(Logger logger, String baseURL, String urlSuffix) {
this(logger, baseURL, urlSuffix, null, null); this(logger, baseURL, urlSuffix, null, null);
} }
@Override @Override
public void action(SlashCommandInteractionEvent event) { public void action(SlashCommandEvent event) {
event.deferReply().queue(); event.deferReply().queue();
try { try {
String result = poll(); String result = poll();
@ -74,6 +72,7 @@ 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);
@ -83,7 +82,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();
@ -98,12 +97,12 @@ public abstract class NumberedSlashCommand implements SlashCommand {
@Override @Override
public List<OptionData> getOptions() { public List<OptionData> getOptions() {
return Collections.emptyList(); return null;
} }
@Override @Override
public List<SubcommandData> getSubcommands() { public List<SubcommandData> getSubcommands() {
return Collections.emptyList(); return null;
} }
} }

View File

@ -1,20 +1,19 @@
package net.Broken.Tools.Command; package net.Broken.Tools.Command;
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.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 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.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
@ -22,56 +21,52 @@ import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
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 * Search all implemented Command interface class and add it to MainBot.commands HashMap
* 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 {} Command:", modules.size()); logger.info("Find " + modules.size() + " Command:");
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) -> {
SlashCommandData command = Commands.slash(k, v.getDescription()); CommandData command = new CommandData(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.setDefaultPermissions(v.getDefaultPermissions()); command.setDefaultEnabled(!v.isDisableByDefault());
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,6 +42,7 @@ public class DayListener extends Thread {
} }
} }
/** /**
* Thread loop * Thread loop
*/ */

View File

@ -1,5 +1,18 @@
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;
@ -7,20 +20,6 @@ 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
*/ */
@ -45,13 +44,18 @@ 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());
@ -60,14 +64,17 @@ 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 {}, ignoring it!", guild.getName()); logger.info("No NSFW chanel found for " + guild.getName() + ", ignoring it!");
} }
} }
} }

View File

@ -1,20 +1,19 @@
package net.Broken.Tools; package net.Broken.Tools;
import java.awt.Color;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo;
import net.Broken.Audio.UserAudioTrack;
import net.Broken.BotConfigLoader; import net.Broken.BotConfigLoader;
import net.Broken.MainBot; import net.Broken.MainBot;
import net.Broken.SpringContext; import net.Broken.SpringContext;
import net.Broken.Audio.UserAudioTrack;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
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 java.awt.*;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
/** /**
* Pre build Message Embed * Pre build Message Embed
*/ */
@ -27,6 +26,7 @@ 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")
@ -63,7 +63,8 @@ public class EmbedMessageUtils {
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);
@ -77,10 +78,10 @@ public class EmbedMessageUtils {
.setColor(Color.red)); .setColor(Color.red));
} }
public static MessageEmbed getInternalError() { public static MessageEmbed getInternalError() {
return buildStandar( return buildStandar(
getError( getError("I... I... I don't feel so good ~~mr stark~~... :thermometer_face: \nPlease contact my developer!")
"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"));
} }
@ -93,8 +94,7 @@ public class EmbedMessageUtils {
} }
public static MessageEmbed getUnautorized() { public static MessageEmbed getUnautorized() {
return buildStandar( return buildStandar(getError("You're not powerful enough to do that slave !").setImage("https://i.imgur.com/0OSsdvW.gif"));
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,4 +118,5 @@ public class EmbedMessageUtils {
.build(); .build();
} }
} }

View File

@ -16,8 +16,7 @@ public class FindContentOnWebPage {
* @return Picture URL * @return Picture URL
* @throws IOException * @throws IOException
*/ */
public static String doYourJob(String url, String divClass, String htmlType) public static String doYourJob(String url, String divClass, String htmlType) throws IOException, InterruptedException {
throws IOException, InterruptedException {
// System.out.println(url); // System.out.println(url);
String source = getSourceUrl(url); String source = getSourceUrl(url);
int divIndex = source.indexOf("class=\"" + divClass); int divIndex = source.indexOf("class=\"" + divClass);
@ -43,8 +42,7 @@ public class FindContentOnWebPage {
HttpRequest request = HttpRequest.newBuilder() HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url)) .uri(URI.create(url))
.header("User-Agent", .header("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")
"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")
.GET() .GET()
.build(); .build();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();

View File

@ -11,6 +11,7 @@ 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/
* *
@ -73,5 +74,6 @@ public class LimitChecker {
logger.debug("Final pass: " + number); logger.debug("Final pass: " + number);
return number; return number;
} }
} }

View File

@ -1,19 +1,18 @@
package net.Broken.Tools.Random.Data; package net.Broken.Tools.Random.Data;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
@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 Result(Random random, String bitsUsed, String bitsLeft, String requestsLeft, String advisoryDelay){
public record Random(List<Integer> data, String completionTime) { public record Random(List<Integer> data, String completionTime){};
};
} }
} }

View File

@ -1,10 +1,9 @@
package net.Broken.Tools.Random; package net.Broken.Tools.Random;
import java.io.IOException; import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.InputStream; import net.Broken.BotConfigLoader;
import java.nio.charset.StandardCharsets; import net.Broken.SpringContext;
import java.util.List; import net.Broken.Tools.Random.Data.RandomData;
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;
@ -15,18 +14,16 @@ 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 com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException;
import java.io.InputStream;
import net.Broken.BotConfigLoader; import java.nio.charset.StandardCharsets;
import net.Broken.SpringContext; import java.util.List;
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();
} }
@ -40,8 +37,7 @@ public class TrueRandom {
// 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, RandomData postData = new RandomData("2.0", "generateIntegers", 41, new RandomData.Params(apiKey, 50, min, max, (max - min) < 50), null, null);
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);
@ -59,6 +55,7 @@ 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

@ -38,4 +38,5 @@ public class Redirection {
return urlReturn; return urlReturn;
} }
} }

View File

@ -1,11 +1,11 @@
package net.Broken.Tools.Settings; package net.Broken.Tools.Settings;
import java.util.ArrayList;
import java.util.List;
import net.Broken.Api.Data.Settings.SettingDescriber; import net.Broken.Api.Data.Settings.SettingDescriber;
import net.Broken.Api.Data.Settings.SettingGroup; import net.Broken.Api.Data.Settings.SettingGroup;
import java.util.ArrayList;
import java.util.List;
public class SettingDescriptionBuilder { public class SettingDescriptionBuilder {
public List<SettingGroup> build(){ public List<SettingGroup> build(){
List<SettingGroup> toReturn = new ArrayList<>(); List<SettingGroup> toReturn = new ArrayList<>();
@ -15,25 +15,28 @@ public class SettingDescriptionBuilder {
toReturn.add(getDailyGroup()); toReturn.add(getDailyGroup());
return toReturn; return toReturn;
} }
private SettingGroup getWelcomeGroup() { private SettingGroup getWelcomeGroup() {
SettingDescriber mainField = new SettingDescriber( SettingDescriber mainField = new SettingDescriber(
"welcome_enable", "welcome_enable",
"Enable Welcome Message", "Enable Welcome Message",
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(
"welcome_chanel_id", "welcome_chanel_id",
"Welcome Message chanel", "Welcome Message chanel",
null, null,
SettingDescriber.TYPE.TEXT_CHANNEL)); SettingDescriber.TYPE.TEXT_CHANNEL
));
fields.add(new SettingDescriber( fields.add(new SettingDescriber(
"welcome_message", "welcome_message",
"Welcome Message", "Welcome Message",
null, null,
SettingDescriber.TYPE.STRING)); SettingDescriber.TYPE.STRING
));
return new SettingGroup( return new SettingGroup(
"Welcome Message", "Welcome Message",
@ -46,14 +49,16 @@ public class SettingDescriptionBuilder {
"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",
@ -67,7 +72,8 @@ public class SettingDescriptionBuilder {
"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",
@ -80,19 +86,22 @@ public class SettingDescriptionBuilder {
"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",

View File

@ -1,13 +1,12 @@
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;

View File

@ -1,11 +1,11 @@
package net.Broken.Tools.Settings; package net.Broken.Tools.Settings;
import java.util.ArrayList;
import java.util.List;
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 java.util.ArrayList;
import java.util.List;
public class SettingValueBuilder { public class SettingValueBuilder {
private final GuildPreferenceEntity guildPreference; private final GuildPreferenceEntity guildPreference;
@ -25,13 +25,19 @@ public class SettingValueBuilder {
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( toReturn.add(new Value(
"welcome_chanel_id", "welcome_chanel_id",
pref.getWelcomeChanelID())); pref.getWelcomeChanelID()
)
);
toReturn.add(new Value( toReturn.add(new Value(
"welcome_message", "welcome_message",
pref.getWelcomeMessage())); pref.getWelcomeMessage()
)
);
return toReturn; return toReturn;
} }
@ -39,10 +45,14 @@ public class SettingValueBuilder {
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( toReturn.add(new Value(
"default_role_id", "default_role_id",
pref.getDefaultRoleId())); pref.getDefaultRoleId()
)
);
return toReturn; return toReturn;
} }
@ -50,7 +60,9 @@ public class SettingValueBuilder {
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;
} }
@ -58,13 +70,19 @@ public class SettingValueBuilder {
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( toReturn.add(new Value(
"auto_voice_base_channel", "auto_voice_base_channel",
pref.getAutoVoiceChannelID())); pref.getAutoVoiceChannelID()
)
);
toReturn.add(new Value( toReturn.add(new Value(
"auto_voice_channel_title", "auto_voice_channel_title",
pref.getAutoVoiceChannelTitle())); pref.getAutoVoiceChannelTitle()
)
);
return toReturn; return toReturn;
} }

View File

@ -2,6 +2,7 @@ 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;
@ -13,10 +14,13 @@ 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() {
@ -25,7 +29,7 @@ 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,20 +1,11 @@
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;
@ -22,6 +13,14 @@ 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 {
@ -29,6 +28,7 @@ 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,6 +40,7 @@ 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() {
@ -59,17 +60,16 @@ public class UserStatsUtils {
logger.debug(userEntity); logger.debug(userEntity);
logger.debug(userEntity.getUserStats()); logger.debug(userEntity.getUserStats());
if (userEntity.getUserStats() == null || userEntity.getUserStats().isEmpty() if (userEntity.getUserStats() == null || userEntity.getUserStats().size() == 0 || userEntity.getUserStats().size() < jdaUser.getMutualGuilds().size()) {
|| userEntity.getUserStats().size() < jdaUser.getMutualGuilds().size()) { logger.debug("Stats not found for " + userEntity.getUsername());
logger.debug("Stats not found for {}", userEntity.getUsername());
List<UserStats> stats; List<UserStats> stats;
if (userEntity.getUserStats() == null || userEntity.getUserStats().isEmpty()) { if (userEntity.getUserStats() == null || userEntity.getUserStats().size() == 0) {
logger.debug("No stats found for user {}, use blank.", jdaUser.getName()); logger.debug("No stats found for user " + jdaUser.getName() + ", use blank.");
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 {} stats don't exist", guid.getName()); logger.debug("Guild " + guid.getName() + " stats don't exist");
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.isEmpty()) { if (userStatsList.size() == 0) {
logger.debug("User stats not found for user {} guild: {}", userEntity.getUsername(), logger.debug("User stats not found for user " + userEntity.getUsername() + " guild: " + member.getGuild().getId());
member.getGuild().getId());
getUserStats(userEntity); getUserStats(userEntity);
userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, member.getGuild().getId()); userStatsList = userStatsRepository.findByUserAndGuildId(userEntity, member.getGuild().getId());
} }
@ -119,42 +119,51 @@ 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).isEmpty()) { if (userStatsRepository.findByUserAndGuildId(userEntity, guildId).size() == 0) {
logger.debug("User stats not found for user {} guild: {}", userEntity.getUsername(), guildId); logger.debug("User stats not found for user " + userEntity.getUsername() + " guild: " + 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);
@ -168,26 +177,23 @@ 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(), GuildStats temp = new GuildStats(stats.getUser().getUsername(), 0, avatar, stats.getVocalTime(), stats.getMessageCount(), stats.getApiCommandCount());
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.isEmpty()) { if (needCache.size() != 0) {
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 '{}'after load, User leave the guild ?", logger.warn("Can't find member '" + stats.getUser().getUsername() + "'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(), GuildStats temp = new GuildStats(stats.getUser().getUsername(), 0, avatar, stats.getVocalTime(), stats.getMessageCount(), stats.getApiCommandCount());
stats.getMessageCount(), stats.getApiCommandCount());
if (stats.getUser().getId().equals(userEntity.getId())) { if (stats.getUser().getId().equals(userEntity.getId())) {
selfGuildStats = temp; selfGuildStats = temp;
} }
@ -206,6 +212,7 @@ 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());
@ -215,8 +222,7 @@ public class UserStatsUtils {
if (i >= 6) { if (i >= 6) {
break; break;
} }
stringBuilder.append(i).append(". ").append(stats.userName).append(" with ").append(stats.total) stringBuilder.append(i).append(". ").append(stats.userName).append(" with ").append(stats.total).append(" points!").append("\n");
.append(" points!").append("\n");
i++; i++;
} }
@ -232,6 +238,7 @@ 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);
@ -246,13 +253,14 @@ public class UserStatsUtils {
@Override @Override
public void run() { public void run() {
while (member.getVoiceState().inAudioChannel()) { while (member.getVoiceState().inVoiceChannel()) {
try { try {
Thread.sleep(10000); Thread.sleep(10000);
if (member.getVoiceState().inAudioChannel()) if (member.getVoiceState().inVoiceChannel())
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();
} }
@ -261,4 +269,5 @@ public class UserStatsUtils {
} }
} }
} }

View File

@ -0,0 +1,26 @@
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

@ -244,6 +244,37 @@ 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