Compare commits

..
30 Commits
Author SHA1 Message Date
stijn 59065dddc8 Use @Slf4j in ReminderScheduler and Reminder, convert null checks to Optional, and enhance logging for error handling and unexpected channel types. 2026-07-12 22:24:03 +02:00
stijn cbe13d3033 Update Gradle wrapper to 9.6.1, upgrade dependencies (Spring Boot 4.1.0, JDA 6.5.0, and others), refine gradlew script, and adjust build configuration for compatibility. 2026-07-12 22:05:09 +02:00
stijn a396b13261 Use @Slf4j in QueriesUserByRole, improve query filtering by active accounts, and refine error handling in CommandSyncNitro. 2025-11-08 21:18:08 +01:00
stijn b0d3498d1c Add .queue() to embed action in CommandSyncNitro for proper execution 2025-11-08 20:48:56 +01:00
stijn 1bd6602421 Add .queue() to embed action in CommandSyncNitro for proper execution 2025-11-08 20:29:14 +01:00
stijn 7e26aba4ab Add .queue() to embed action in CommandSyncNitro for proper execution 2025-11-08 20:28:54 +01:00
stijn 47eb88cbae Use Lombok's @Slf4j in CommandSyncNitro and add logging for database changes during member checks. 2025-11-08 20:24:49 +01:00
stijn a0b3d2167a Add CommandSyncNitro for synchronizing Nitro roles and update related database queries. 2025-11-08 20:24:07 +01:00
stijn 2c1088ef2e Update from v5 -> v6 for JDA 2025-11-08 19:35:28 +01:00
stijn 3d868a109d Refactor build.gradle.kts: reorder plugins, configure bootJar and shadowJar, optimize jar task setup, and update main class attribute. 2025-09-11 22:35:02 +02:00
stijn e947275409 Update CommandSeen: replace "grove" with "bayou" in valid servers, switch to InteractionContextType.GUILD. 2025-09-11 22:11:36 +02:00
stijn 0960795d40 Remove redundant jar task configuration in build.gradle.kts. 2025-08-08 23:31:57 +02:00
stijn 7863b3f62d Add AutoThread listener for creating threads in specific channels. 2025-08-08 22:38:05 +02:00
stijn 003c75c391 Replace Logger with Lombok's @Slf4j annotation in ContactEndpoint and update log method calls. 2025-08-08 21:01:34 +02:00
auto 81b53cd1f8 Update dependencies and build process
Upgraded multiple dependencies including Spring Boot, JDA, and Configurate to their latest versions. Updated Java toolchain to version 21. Added the Versions plugin for dependency version management. Modified Jenkins build process to use `shadowJar`.
2025-06-20 23:10:46 +02:00
auto 34f9559d10 Change join-time option type to INTEGER
Adjusted the option type for 'join-time' from NUMBER to INTEGER for clarity and accuracy. This ensures proper data representation and aligns with intended usage.
2024-08-26 20:25:04 +02:00
auto f2864ade8a Add UPSERT behavior to setJoinDate query
Modified the SQL query in the setJoinDate method to use "ON DUPLICATE KEY UPDATE" for updating the date if the userId already exists. This ensures that duplicate entries are handled correctly by updating the existing record rather than creating a new one.
2024-08-26 19:15:03 +02:00
auto cd356121b7 Update CommandStaffJoinDate descriptions
Improved the descriptions of the options for the CommandStaffJoinDate command. The "staff" and "join-time" options now have clearer descriptions, making their purposes more understandable for users.
2024-08-25 19:50:38 +02:00
auto 1f706b69b8 Refactor CommandStaffJoinDate initialization
Correctly initialize and return the CommandData object for cleaner code. This change ensures proper usage of the command data and handles the auto-complete interaction correctly.
2024-08-25 19:47:34 +02:00
auto 8f6d1137ae Remove autocomplete from command options
Disabled autocomplete for "staff" and "join-time" options in the CommandStaffJoinDate constructor. This change simplifies the command interface by eliminating unnecessary suggestions.
2024-08-25 19:45:58 +02:00
auto 8a65c27bac Add command for managing staff join dates
Implemented `CommandStaffJoinDate` to allow viewing and setting staff join dates. Included methods in `QueriesStaffJoinDate` for database interactions and defined the `JoinDate` record to encapsulate join date information.
2024-08-25 19:39:43 +02:00
auto cbf51f3fc8 Added Jenkins file
Added Jenkins file to automate builds
2024-08-07 00:26:11 +02:00
auto bd9ecc2677 Added Jenkins file
Added Jenkins file to automate builds
2024-08-07 00:25:57 +02:00
auto 0e0db7cb17 Added Jenkins file
Added Jenkins file to automate builds
2024-08-07 00:25:19 +02:00
auto 31ebc7116b Merge branch 'refs/heads/forms' 2024-08-07 00:21:25 +02:00
auto 09db7b3c16 Added Jenkins file
Added Jenkins file to automate builds
2024-08-07 00:21:05 +02:00
auto 27f1920081 Create event management system, added event notifier for community events
Added functionalities to create and manage events, including the creation of necessary database tables, context menus, modals, and scheduling tasks. Introduced `UserToMessageTracker` utility for tracking user messages within modals.
2024-08-07 00:18:40 +02:00
auto 994cd7a85f Updated JDA and gradle + Refactor modal methods to match the JDA update
Refactor modals to use `addActionRow` instead of `addActionRows`. Updated JDA dependency to version 5.0.2 and upgraded Gradle to version 8.5.
2024-08-07 00:17:58 +02:00
auto ead56c4585 Merge branch 'master' into forms
# Conflicts:
#	src/main/java/com/alttd/AltitudeBot.java
2024-04-28 17:06:27 +02:00
auto 964bfc85fa Initial commit for handling forms 2024-03-31 11:02:51 +02:00
78 changed files with 1832 additions and 411 deletions
Vendored
+20
View File
@@ -0,0 +1,20 @@
pipeline {
agent any
stages {
stage('Gradle') {
steps {
sh 'bash ./gradlew shadowJar'
}
}
stage('Archive') {
steps {
archiveArtifacts artifacts: 'build/libs/', followSymlinks: false
}
}
stage('discord') {
steps {
discordSend description: "Build: ${BUILD_NUMBER}", showChangeset: true, result: currentBuild.currentResult, title: currentBuild.fullProjectName, webhookURL: env.discordwebhook
}
}
}
}
+30 -18
View File
@@ -1,8 +1,10 @@
plugins {
id("java")
id("com.github.johnrengelman.shadow") version "7.1.0"
id("org.springframework.boot") version("4.1.0")
id("io.spring.dependency-management") version "1.1.5"
id("maven-publish")
id("com.gradleup.shadow") version "9.5.1"
id("com.github.ben-manes.versions") version "0.52.0"
}
group = "com.alttd"
@@ -11,7 +13,7 @@ description = "Altitude Discord Bot."
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
languageVersion.set(JavaLanguageVersion.of(21))
}
}
@@ -32,42 +34,52 @@ tasks {
options.encoding = Charsets.UTF_8.name()
}
withType<Jar> {
bootJar {
enabled = false // Disable the bootJar task
}
jar {
enabled = true // Enable the jar task
manifest {
attributes["Main-Class"] = "${rootProject.group}.${project.name}"
attributes["Main-Class"] = "com.alttd.AltitudeBot"
}
}
shadowJar {
archiveFileName.set(rootProject.name + ".jar")
mergeServiceFiles()
manifest {
attributes["Main-Class"] = "com.alttd.AltitudeBot" // Set your main class directly
}
}
build {
dependsOn(shadowJar)
}
jar {
enabled = false
}
}
dependencies {
// JDA
implementation("net.dv8tion:JDA:5.0.0-beta.19") {
implementation("net.dv8tion:JDA:6.5.0") {
exclude("opus-java") // exclude audio
}
// MySQL
implementation("mysql:mysql-connector-java:8.0.33")
implementation("com.mysql:mysql-connector-j:9.7.0")
// Configurate
implementation("org.spongepowered:configurate-yaml:4.1.2")
implementation("org.spongepowered:configurate-yaml:4.2.0")
// Excel
implementation("org.apache.poi:poi:5.2.0")
implementation("org.apache.poi:poi-ooxml:5.2.0")
implementation("org.apache.poi:poi:5.5.1")
implementation("org.apache.poi:poi-ooxml:5.5.1")
// Other stuff?
compileOnly("org.projectlombok:lombok:1.18.30")
annotationProcessor("org.projectlombok:lombok:1.18.24")
compileOnly("org.projectlombok:lombok:1.18.46")
annotationProcessor("org.projectlombok:lombok:1.18.46")
implementation("com.alttd:AltitudeLogs:1.0")
}
implementation("org.springframework.boot:spring-boot-starter-web:4.1.0")
implementation("org.springframework.boot:spring-boot-starter-validation:4.1.0")
implementation("com.google.code.gson:gson:2.14.0")
testImplementation(platform("org.junit:junit-bom:6.1.1"))
testImplementation("org.junit.jupiter:junit-jupiter")
}
Binary file not shown.
+5 -1
View File
@@ -1,5 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+179 -116
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,81 +15,114 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# gradlew start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh gradlew
#
# 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/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/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
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,88 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, 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" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# 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" "$@"
Vendored
+28 -35
View File
@@ -13,19 +13,22 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem gradlew startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Set local scope for the variables, and ensure extensions are enabled
setlocal EnableExtensions
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,15 +43,15 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
"%COMSPEC%" /c exit 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
@@ -56,34 +59,24 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
"%COMSPEC%" /c exit 1
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
@rem Execute gradlew
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%
+32 -7
View File
@@ -11,28 +11,47 @@ import lombok.Getter;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.requests.GatewayIntent;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
@SpringBootApplication
public class AltitudeBot {
private JDA jda;
@Getter
private static AltitudeBot instance;
private static String path;
public static void main(String[] args) {
if (args.length == 0) { //TODO change scripts so it works with this
System.out.println("Please give the location for the configs as an arg");
return;
}
path = args[0];
instance = new AltitudeBot();
instance.start();
instance.start(args);
// SpringApplication.run(AltitudeBot.class, args);
new SpringApplicationBuilder(AltitudeBot.class)
.web(WebApplicationType.SERVLET) // .REACTIVE, .SERVLET
.run(args);
}
private void start() {
private void start(String[] args) {
// Logger.altitudeLogs.info("Starting spring application");
// SpringApplication.run(AltitudeBot.class, args);
Logger.altitudeLogs.info("Starting bot...");
initConfigs();
jda = JDABuilder.createDefault(SettingsConfig.TOKEN,
GatewayIntent.GUILD_MEMBERS,
GatewayIntent.GUILD_MODERATION,
GatewayIntent.GUILD_EMOJIS_AND_STICKERS,
GatewayIntent.GUILD_EXPRESSIONS,
GatewayIntent.GUILD_WEBHOOKS,
GatewayIntent.GUILD_PRESENCES,
GatewayIntent.GUILD_MESSAGES,
@@ -50,11 +69,11 @@ public class AltitudeBot {
// } catch (IllegalArgumentException e) {
// Logger.exception(e);
// }
initListeners();
initListeners(args);
}
private void initListeners() {
jda.addEventListener(new JDAListener(jda));
private void initListeners(String[] args) {
jda.addEventListener(new JDAListener(jda, args));
}
private void initConfigs() {
@@ -65,7 +84,13 @@ public class AltitudeBot {
public String getDataFolder() {
try {
return new File(AltitudeBot.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getPath();
// return new File(AltitudeBot.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getPath();
File file = Path.of(new URI("file://"+ path)).toFile();
if (!file.exists() || !file.canWrite() || !file.isDirectory()) {
System.out.println("Directory does not exist or can't be written to: " + file.getPath());
return null;
}
return file.getPath();
} catch (URISyntaxException e) {
Logger.altitudeLogs.error("Unable to retrieve config directory");
Logger.altitudeLogs.error(e);
@@ -0,0 +1,6 @@
package com.alttd.DTO;
import java.time.Instant;
public record JoinDate (long userId, Instant joinDate){
}
@@ -3,20 +3,17 @@ package com.alttd.buttonManager;
import com.alttd.buttonManager.buttons.autoReminder.ButtonAccepted;
import com.alttd.buttonManager.buttons.autoReminder.ButtonInProgress;
import com.alttd.buttonManager.buttons.autoReminder.ButtonRejected;
import com.alttd.buttonManager.buttons.eventButton.EventButton;
import com.alttd.buttonManager.buttons.remindMeConfirm.ButtonRemindMeCancel;
import com.alttd.buttonManager.buttons.remindMeConfirm.ButtonRemindMeConfirm;
import com.alttd.buttonManager.buttons.suggestionReview.ButtonSuggestionReviewAccept;
import com.alttd.buttonManager.buttons.suggestionReview.ButtonSuggestionReviewDeny;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.RestAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -34,6 +31,7 @@ public class ButtonManager extends ListenerAdapter {
buttons.add(new ButtonAccepted());
buttons.add(new ButtonInProgress());
buttons.add(new ButtonRejected());
buttons.add(new EventButton());
}
public void addButton(DiscordButton button) {
@@ -46,7 +44,7 @@ public class ButtonManager extends ListenerAdapter {
@Override
public void onButtonInteraction(@NotNull ButtonInteractionEvent event) {
String buttonId = event.getButton().getId();
String buttonId = event.getButton().getCustomId();
Optional<DiscordButton> first = buttons.stream()
.filter(discordModal -> discordModal.getButtonId().equalsIgnoreCase(buttonId))
.findFirst();
@@ -67,9 +65,7 @@ public class ButtonManager extends ListenerAdapter {
Optional<DiscordButton> first = buttons.stream()
.filter(discordButton -> discordButton.getButtonId().equalsIgnoreCase(buttonId))
.findFirst();
if (first.isEmpty())
return null;
return first.get().getButton();
return first.map(DiscordButton::getButton).orElse(null);
}
}
@@ -1,7 +1,7 @@
package com.alttd.buttonManager;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
public abstract class DiscordButton {
@@ -5,16 +5,15 @@ import com.alttd.schedulers.ReminderScheduler;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import java.awt.*;
import java.util.Collections;
import java.util.Objects;
public class ButtonAccepted extends DiscordButton {
@Override
@@ -28,7 +27,7 @@ public class ButtonAccepted extends DiscordButton {
if (!ButtonReminderUtil.shouldExecute(message, event))
return;
Logger.altitudeLogs.debug("Accepting reminder");
MessageEmbed embed = message.getEmbeds().get(0);
MessageEmbed embed = message.getEmbeds().getFirst();
EmbedBuilder embedBuilder = new EmbedBuilder(embed).setColor(Color.GREEN);
ReminderScheduler.getInstance(event.getJDA()).removeReminder(message.getIdLong());
message.editMessageEmbeds(embedBuilder.build()).queue();
@@ -4,10 +4,10 @@ import com.alttd.buttonManager.DiscordButton;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import java.awt.*;
@@ -5,16 +5,15 @@ import com.alttd.schedulers.ReminderScheduler;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import java.awt.*;
import java.util.Collections;
import java.util.Objects;
public class ButtonRejected extends DiscordButton {
@Override
@@ -0,0 +1,101 @@
package com.alttd.buttonManager.buttons.eventButton;
import com.alttd.AltitudeBot;
import com.alttd.buttonManager.DiscordButton;
import com.alttd.database.queries.events.Event;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
public class EventButton extends DiscordButton {
public EventButton() {
}
@Override
public String getButtonId() {
return "event_button";
}
@Override
public void execute(ButtonInteractionEvent event) {
Event eventForButton = Event.getEvent(event.getMessageIdLong());
if (eventForButton == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Event not found")).setEphemeral(true).queue();
return;
}
Member member = event.getMember();
if (member == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This button can only be used within a guild")).setEphemeral(true).queue();
return;
}
if (Instant.now().isAfter(eventForButton.getStartTime())) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to process you joining" + eventForButton.getTitle() + ", the event might have ended!")).setEphemeral(true).queue();
return;
}
Optional<Role> any = member.getRoles().stream().filter(role -> role.getIdLong() == eventForButton.getRoleId()).findAny();
if (any.isPresent()) {
updateJoinedEventUsersInEmbed(eventForButton);
event.replyEmbeds(Util.genericSuccessEmbed("Success", "Removed you from " + eventForButton.getTitle() + "!")).setEphemeral(true).queue();
try {
eventForButton.getRole().getGuild().removeRoleFromMember(member, eventForButton.getRole()).queue();
} catch (Exception e) {
Logger.altitudeLogs.error(e);
}
return;
}
try {
eventForButton.getRole().getGuild().addRoleToMember(member, eventForButton.getRole()).queue();
} catch (Exception e) {
Logger.altitudeLogs.error(e);
}
if (updateJoinedEventUsersInEmbed(eventForButton)) {
event.replyEmbeds(Util.genericSuccessEmbed("Success", "You joined " + eventForButton.getTitle() + "!")).setEphemeral(true).queue();
} else {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Failed to add you to the event, contact an admin for help if needed")).setEphemeral(true).queue();
}
}
@Override
public Button getButton() {
return Button.primary(getButtonId(), "Join Event");
}
private boolean updateJoinedEventUsersInEmbed(Event event) {
Optional<Message> optionalMessage = event.getMessage();
if (optionalMessage.isEmpty()) {
Logger.altitudeLogs.error("Unable to find event message");
return false;
}
Message message = optionalMessage.get();
List<MessageEmbed> embeds = message.getEmbeds();
if (embeds.isEmpty()) {
Logger.altitudeLogs.error("Unable to find event embed");
return false;
}
EmbedBuilder builder = new EmbedBuilder(embeds.get(0));
builder.clearFields()
.addField("Event Start", "<t:" + event.getStartTime().getEpochSecond() + ":F>", true);
Guild guildById = AltitudeBot.getInstance().getJDA().getGuildById(event.getGuildId());
if (guildById != null) {
List<Member> membersWithRole = guildById.getMembersWithRoles(event.getRole());
builder.addField("Participants", String.valueOf(membersWithRole.size()), true);
}
MessageEmbed updatedEmbed = builder.build();
message.editMessageEmbeds(updatedEmbed).queue();
return true;
}
}
@@ -4,8 +4,8 @@ import com.alttd.buttonManager.DiscordButton;
import com.alttd.database.queries.Poll.Poll;
import com.alttd.database.queries.Poll.PollButtonClicksQueries;
import com.alttd.util.Util;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import java.util.HashSet;
@@ -1,13 +1,10 @@
package com.alttd.buttonManager.buttons.remindMeConfirm;
import com.alttd.buttonManager.DiscordButton;
import com.alttd.database.queries.QueriesReminders.Reminder;
import com.alttd.util.Util;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ButtonRemindMeCancel extends DiscordButton {
@@ -5,9 +5,9 @@ import com.alttd.database.queries.QueriesReminders.QueriesReminders;
import com.alttd.database.queries.QueriesReminders.Reminder;
import com.alttd.schedulers.ReminderScheduler;
import com.alttd.util.Util;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import java.util.HashMap;
import java.util.List;
@@ -6,6 +6,7 @@ import com.alttd.database.queries.commandOutputChannels.OutputType;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
@@ -16,7 +17,6 @@ import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
@@ -5,13 +5,13 @@ import com.alttd.database.queries.commandOutputChannels.CommandOutputChannels;
import com.alttd.database.queries.commandOutputChannels.OutputType;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.RestAction;
import java.awt.*;
@@ -42,6 +42,7 @@ public class CommandManager extends ListenerAdapter {
new CommandHelp(jda, this),
new CommandPoll(jda, this, buttonManager),
new CommandSuggestion(jda, modalManager, this),
new CommandSyncNitro(jda, this),
new CommandSuggestCrateItem(jda, modalManager, this),
new CommandSetOutputChannel(jda, this),
new CommandUpdateCommands(jda, this),
@@ -55,6 +56,7 @@ public class CommandManager extends ListenerAdapter {
new CommandSoftLock(jda, this, lockedChannel),
new CommandDataSuggestions(jda, this),
new CommandAuction(jda, this, selectMenuManager),
new CommandStaffJoinDate(jda, this),
new CommandBal());
}
@@ -11,6 +11,7 @@ import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
@@ -31,9 +32,9 @@ public class CommandManage extends DiscordCommand {
.addOption(OptionType.STRING, "command", "Name of the command to enable", true, true),
new SubcommandData("disable", "Disable a command")
.addOption(OptionType.STRING, "command", "Name of the command to disable", true, true)
)
)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR))
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerSubOptions(subOptionsMap,
new SubCommandEnable(commandManager, contextMenuManager, null, this),
new SubCommandDisable(commandManager, null, this)
@@ -10,8 +10,11 @@ import com.alttd.schedulers.AuctionScheduler;
import com.alttd.selectMenuManager.SelectMenuManager;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.selections.SelectMenu;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
@@ -25,7 +28,6 @@ import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import net.dv8tion.jda.api.utils.AttachedFile;
@@ -36,6 +38,7 @@ import java.time.Instant;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Slf4j
public class CommandAuction extends DiscordCommand {
private final CommandData commandData;
@@ -127,7 +130,7 @@ public class CommandAuction extends DiscordCommand {
return;
}
message.editMessageComponents().setActionRow(selectMenu).queue();
message.editMessageComponents(ActionRow.of(selectMenu)).queue();
AuctionScheduler auctionScheduler = AuctionScheduler.getInstance();
if (auctionScheduler == null) {
@@ -142,15 +145,14 @@ public class CommandAuction extends DiscordCommand {
private void addScreenshot(Message.Attachment screenshot, Message message) {
String dataFolder = AltitudeBot.getInstance().getDataFolder();
Path parent = Path.of(dataFolder).getParent();
Path path = Path.of(parent.toString() + UUID.randomUUID() + "." + screenshot.getFileExtension());
Path path = Path.of(dataFolder + UUID.randomUUID() + "." + screenshot.getFileExtension());
screenshot.getProxy().downloadToFile(path.toFile()).whenComplete((file, throwable) ->
message.editMessageAttachments(AttachedFile.fromData(file)).queue(done -> file.delete(), failed -> {
Util.handleFailure(failed);
file.delete();
}))
.exceptionally(e -> {
e.printStackTrace();
log.error("Failed to add screenshot to auction message", e);
return null;
});
}
@@ -7,7 +7,6 @@ import com.alttd.util.Util;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
@@ -15,6 +14,7 @@ import net.dv8tion.jda.api.entities.channel.forums.ForumTag;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
@@ -35,7 +35,7 @@ public class CommandDataSuggestions extends DiscordCommand {
this.commandManager = commandManager;
this.commandData = Commands.slash(getName(), "Get data about suggestions from the forum channel")
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR))
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -8,10 +8,11 @@ import com.alttd.util.Util;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.Collections;
@@ -26,7 +27,7 @@ public class CommandEvidence extends DiscordCommand {
commandData = Commands.slash(getName(), "Open suggestion form.")
.setDefaultPermissions(DefaultMemberPermissions.DISABLED)
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -10,6 +10,7 @@ import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
@@ -32,7 +33,7 @@ public class CommandFlag extends DiscordCommand {
this.commandData = Commands.slash(getName(), "Show flags for a user")
.addOption(OptionType.STRING, "user", "The user to show flags for", true)
.setDefaultPermissions(DefaultMemberPermissions.ENABLED)
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -11,6 +11,7 @@ import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.AutoCompleteQuery;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
@@ -33,7 +34,7 @@ public class CommandHelp extends DiscordCommand {
commandData = Commands.slash(getName(), "Show info about all commands or a specific command.")
.addOption(OptionType.STRING, "command", "Command to get more info about", true , true)
.setDefaultPermissions(DefaultMemberPermissions.ENABLED)
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -12,6 +12,7 @@ import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
@@ -20,8 +21,8 @@ import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.requests.RestAction;
import java.awt.*;
import java.util.List;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -34,7 +35,7 @@ public class CommandHistory extends DiscordCommand {
.addOption(OptionType.STRING, "user", "The user to show history for", true)
.addOption(OptionType.STRING, "type", "The type of punishment to show", false, true)
.setDefaultPermissions(DefaultMemberPermissions.ENABLED)
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -11,12 +11,13 @@ import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.AutoCompleteQuery;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.modals.Modal;
import java.util.Calendar;
import java.util.Collections;
@@ -35,7 +36,7 @@ public class CommandRemindMe extends DiscordCommand {
.addOption(OptionType.CHANNEL, "channel", "The channel to send the reminder in", true)
.addOption(OptionType.STRING, "fromnow", "How long from now the reminder should send", true, true)
.setDefaultPermissions(DefaultMemberPermissions.ENABLED)
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -13,6 +13,7 @@ import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
@@ -30,12 +31,12 @@ import java.util.concurrent.TimeUnit;
public class CommandSeen extends DiscordCommand {
private final CommandData commandData;
private static final List<String> validServers = List.of("lobby", "creative", "grove");
private static final List<String> validServers = List.of("lobby", "creative", "bayou");
public CommandSeen(JDA jda, CommandManager commandManager) {
commandData = Commands.slash(getName(), "Check when a player was last online.")
.addOption(OptionType.STRING, "playername", "The playername or uuid you want to check.", true, false)
.setGuildOnly(true)
.setContexts(InteractionContextType.GUILD)
.setDefaultPermissions(DefaultMemberPermissions.ENABLED);
Util.registerCommand(commandManager, jda, commandData, getName());
@@ -13,6 +13,7 @@ import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.AutoCompleteQuery;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
@@ -34,7 +35,7 @@ public class CommandSetOutputChannel extends DiscordCommand {
.addOption(OptionType.STRING, "type", "The type of output channel", true, true)
.addOption(OptionType.CHANNEL, "channel", "The channel the specified output should go into", true)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR))
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -10,6 +10,7 @@ import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
@@ -31,7 +32,7 @@ public class CommandSoftLock extends DiscordCommand {
.addOption(OptionType.STRING, "state", "Set the soft lock \"on\" or \"off\"", true, true)
.addOption(OptionType.CHANNEL, "channel", "Channel to change soft lock state for", true)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR))
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -0,0 +1,122 @@
package com.alttd.commandManager.commands;
import com.alttd.DTO.JoinDate;
import com.alttd.commandManager.CommandManager;
import com.alttd.commandManager.DiscordCommand;
import com.alttd.database.queries.QueriesStaffJoinDate;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class CommandStaffJoinDate extends DiscordCommand {
private final CommandData commandData;
public CommandStaffJoinDate(JDA jda, CommandManager commandManager) {
this.commandData = Commands.slash(getName(), "View join date for staff members, or add them manually")
.addOption(OptionType.MENTIONABLE, "staff", "The staff member to set/check the join date for", false, false)
.addOption(OptionType.INTEGER, "join-time", "The join date to set", false, false)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR))
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@Override
public String getName() {
return "staff-join-date";
}
@Override
public void execute(SlashCommandInteractionEvent event) {
event.deferReply(true).queue(interactionHook -> processCommand(event, interactionHook));
}
private void processCommand(SlashCommandInteractionEvent event, InteractionHook interactionHook) {
OptionMapping staff = event.getOption("staff");
if (staff == null) {
interactionHook.editOriginalEmbeds(getFullStaffEmbed()).queue();
return;
}
Member member = staff.getAsMember();
if (member == null) {
interactionHook.editOriginalEmbeds(Util.genericErrorEmbed("Invalid member", String.format("%s is not a valid member", staff.getAsMentionable().getAsMention()))).queue();
return;
}
OptionMapping option = event.getOption("join-time");
if (option == null) {
interactionHook.editOriginalEmbeds(getStaffEmbed(member.getIdLong())).queue();
return;
}
long time = option.getAsLong();
Instant instant = Instant.ofEpochSecond(time);
if (instant.isAfter(Instant.now())) {
interactionHook.editOriginalEmbeds(Util.genericErrorEmbed("Invalid time", "The time must be in the past")).queue();
return;
}
QueriesStaffJoinDate.setJoinDate(member.getIdLong(), instant);
interactionHook.editOriginalEmbeds(Util.genericSuccessEmbed(
String.format("Set join date for %s", member.getAsMention()),
String.format("Set to <t:%d:R>", instant.getEpochSecond())))
.queue();
}
private MessageEmbed getStaffEmbed(long userId) {
Optional<JoinDate> joinDate = QueriesStaffJoinDate.getJoinDate(userId);
return joinDate.map(date -> new EmbedBuilder()
.setTitle("Join date for %s".formatted(userId))
.setDescription(String.format("<t:%d:R>", date.joinDate().getEpochSecond()))
.build())
.orElseGet(() -> Util.genericErrorEmbed("No join date found", String.format("No join date found for <@%s>", userId)));
}
private MessageEmbed getFullStaffEmbed() {
EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setTitle("All staff join dates");
List<JoinDate> allJoinDates = QueriesStaffJoinDate.getAllJoinDates();
if (allJoinDates == null || allJoinDates.isEmpty()) {
embedBuilder.setDescription("No staff join dates found.");
} else {
embedBuilder.setDescription(allJoinDates.stream().map(joinDate ->
"<@%d>: <t:%d:R>".formatted(joinDate.userId(), joinDate.joinDate().getEpochSecond()))
.collect(Collectors.joining("\n")));
}
return embedBuilder.build();
}
@Override
public void suggest(CommandAutoCompleteInteractionEvent event) {
event.replyChoiceStrings(List.of()).queue();
}
@Override
public String getHelpMessage() {
return null;
}
@Override
public CommandData getCommandData() {
return commandData;
}
}
@@ -7,10 +7,11 @@ import com.alttd.util.Util;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.Collections;
@@ -24,7 +25,7 @@ public class CommandSuggestCrateItem extends DiscordCommand {
this.modalManager = modalManager;
commandData = Commands.slash(getName(), "Open crate item suggestion form.")
.setGuildOnly(true)
.setContexts(InteractionContextType.GUILD)
.setDefaultPermissions(DefaultMemberPermissions.ENABLED);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -8,26 +8,25 @@ import com.alttd.util.Util;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.Collections;
public class CommandSuggestion extends DiscordCommand {
private final CommandManager commandManager;
private final CommandData commandData;
private final ModalManager modalManager;
public CommandSuggestion(JDA jda, ModalManager modalManager, CommandManager commandManager) {
this.commandManager = commandManager;
this.modalManager = modalManager;
commandData = Commands.slash(getName(), "Open suggestion form.")
.setGuildOnly(true)
.setContexts(InteractionContextType.GUILD)
.setDefaultPermissions(DefaultMemberPermissions.ENABLED);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -0,0 +1,138 @@
package com.alttd.commandManager.commands;
import com.alttd.commandManager.CommandManager;
import com.alttd.commandManager.DiscordCommand;
import com.alttd.config.MessagesConfig;
import com.alttd.database.queries.QueriesUserByRole;
import com.alttd.database.queries.QueriesUserDiscordId;
import com.alttd.util.Util;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
public class CommandSyncNitro extends DiscordCommand {
private final CommandData commandData;
private final JDA jda;
public CommandSyncNitro(JDA jda, CommandManager commandManager) {
this.jda = jda;
commandData = Commands.slash(getName(), "Sync nitro users.")
.setContexts(InteractionContextType.GUILD)
.setDefaultPermissions(DefaultMemberPermissions.DISABLED);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@Override
public String getName() {
return "syncnitro";
}
@Override
public void execute(SlashCommandInteractionEvent event) {
Guild guildById = jda.getGuildById(141644560005595136L);
if (guildById == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find guild."))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
ReplyCallbackAction replyCallbackAction = event.deferReply(true);
QueriesUserByRole.getUserIdsByRole("nitro").whenCompleteAsync((optionalUserIdList, error) -> {
if (error != null) {
log.error("Unable to retrieve user list.", error);
replyCallbackAction
.setEmbeds(Util.genericErrorEmbed("Error", "Unable to retrieve user list."))
.queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
if (optionalUserIdList.isEmpty()) {
replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "No users found."))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
checkAllMembers(optionalUserIdList.get(), guildById, replyCallbackAction);
});
Role roleById = guildById.getRoleById(585557866275012633L);
guildById.getMembersWithRoles(roleById).forEach(member -> {
QueriesUserDiscordId.addRoleIfMissing(member.getIdLong(), "nitro").thenAccept(success -> {
log.info("Added nitro role to user {}.", member.getIdLong());
});
});
}
private void checkAllMembers(List<Long> userIdList, Guild guildById, ReplyCallbackAction replyCallbackAction) {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
for (int i = 0; i < userIdList.size(); i++) {
long userId = userIdList.get(i);
scheduler.schedule(() -> {
Member member = guildById.getMemberById(userId);
if (member == null) {
guildById.retrieveMemberById(userId)
.queue(retrievedMember -> checkMember(retrievedMember, userId),
error -> checkMember(null, userId));
} else {
checkMember(member, userId);
}
}, i, TimeUnit.SECONDS);
}
replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "Syncing " + userIdList.size() + " users in background"))
.queue(RestAction.getDefaultSuccess(), Util::handleFailure);
scheduler.shutdown();
}
private void checkMember(Member member, long userId) {
if (member == null) {
QueriesUserDiscordId.removeLinkedUserByDiscordId(userId).thenAccept(success -> {
log.info("User {} not found in guild. Removed from database.", userId);
});
log.info("User {} not found in guild. Removing from database.", userId);
return;
}
boolean hasNitro = member.getRoles().stream().anyMatch(role -> role.getIdLong() == 585557866275012633L);
if (!hasNitro) {
log.info("User {} does not have nitro. Removing nitro role from database.", userId);
QueriesUserDiscordId.removeRole(userId, "nitro").thenAccept(success -> {
log.info("User {} does not have nitro. Removed nitro role from database.", userId);
});
}
}
@Override
public void suggest(CommandAutoCompleteInteractionEvent event) {
event.replyChoices(Collections.emptyList())
.queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
@Override
public String getHelpMessage() {
return MessagesConfig.HELP_SYNC_NITRO;
}
@Override
public CommandData getCommandData() {
return commandData;
}
}
@@ -8,6 +8,7 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
@@ -27,7 +28,7 @@ public class CommandUpdateCommands extends DiscordCommand {
this.commandManager = commandManager;
this.commandData = Commands.slash(getName(), "Updates all commands for this bot in this guild")
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR))
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerCommand(commandManager, jda, commandData, getName());
}
@@ -4,13 +4,13 @@ import com.alttd.buttonManager.ButtonManager;
import com.alttd.commandManager.CommandManager;
import com.alttd.commandManager.DiscordCommand;
import com.alttd.commandManager.SubOption;
import com.alttd.schedulers.PollTimerTask;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
@@ -52,7 +52,7 @@ public class CommandPoll extends DiscordCommand {
new SubcommandData("update_total_votes", "Update the total vote count incase it's out of sync")
.addOption(OptionType.STRING, "message_id", "Id of the poll you want to update the total vote count for", true))
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR))
.setGuildOnly(true);
.setContexts(InteractionContextType.GUILD);
Util.registerSubOptions(subOptionsMap,
new SubCommandAdd(null,this),
new SubCommandAddButton(null, this, buttonManager),
@@ -12,12 +12,12 @@ import com.alttd.templates.Template;
import com.alttd.util.Logger;
import com.alttd.util.OptionMappingParsing;
import com.alttd.util.Util;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.actionrow.ActionRowChildComponent;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
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.ItemComponent;
import java.util.ArrayList;
import java.util.List;
@@ -102,7 +102,9 @@ public class SubCommandAddButton extends SubCommand {
}
PollButton pollButton = any.get();
List<ActionRow> actionRows = message.getActionRows();
List<ActionRow> actionRows = message.getComponents().stream()
.filter(component -> component instanceof ActionRow)
.map(a -> (ActionRow) a).toList();
if (rowId > 1) {//todo fix if needed in the future
hook.editOriginalEmbeds(Util.genericErrorEmbed("Error",
"Polls have only been set up to handle 1 row if you need more than one row update the code."))
@@ -110,14 +112,15 @@ public class SubCommandAddButton extends SubCommand {
return;
}
List<ItemComponent> components;
List<ActionRowChildComponent> components;
if (!actionRows.isEmpty()) {
components = actionRows.get(0).getComponents();
} else
components = new ArrayList<>(actionRows.getFirst().getComponents());
} else {
components = new ArrayList<>();
}
components.add(pollButton.getButton());
message.editMessageComponents().setActionRow(components).queue();
message.editMessageComponents(ActionRow.of(components)).queue();
hook.editOriginalEmbeds(Util.genericSuccessEmbed("Success", "Added a button")).queue();
}
@@ -0,0 +1,52 @@
package com.alttd.communication.contact;
import com.alttd.AltitudeBot;
import com.alttd.communication.formData.ContactFormData;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.CompletableFuture;
@Slf4j
@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/api/contact")
public class ContactEndpoint {
@PostMapping("/submitContactForm")
public CompletableFuture<ResponseEntity<String>> sendFormToDiscord(@Valid @RequestBody ContactFormData formData) {
log.debug("Sending form to Discord: {}", formData);
MessageEmbed messageEmbed = formData.toMessageEmbed();
Guild guild = AltitudeBot.getInstance().getJDA().getGuildById(514920774923059209L);
if (guild == null) {
log.error("Unable to retrieve staff guild");
return CompletableFuture.completedFuture(ResponseEntity.internalServerError().body("Failed to submit form to Discord"));
}
TextChannel channel = guild.getChannelById(TextChannel.class, 514922567883292673L);
if (channel == null) {
log.error("Unable to retrieve contact form channel");
return CompletableFuture.completedFuture(ResponseEntity.internalServerError().body("Failed to submit form to Discord"));
}
return CompletableFuture.supplyAsync(() -> {
try {
Message complete = channel.sendMessageEmbeds(messageEmbed).complete();
if (complete != null)
return ResponseEntity.ok("");
} catch (Exception exception) {
log.error("Failed to send message to Discord", exception);
}
return ResponseEntity.internalServerError().body("Failed to submit form to Discord");
});
}
}
@@ -0,0 +1,51 @@
package com.alttd.communication.formData;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;
import org.hibernate.validator.constraints.Length;
import java.awt.*;
public class ContactFormData extends Form {
public ContactFormData(String username, String email, String question) {
this.username = username;
this.email = email;
this.question = question;
}
@NotEmpty(message = "You have to provide a username")
@Length(min = 3, max = 16, message = "Usernames have to be between 3 and 16 characters")
@Pattern(regexp = "[a-zA-Z-0-9_]{3,16}", message = "Your username has to be a valid Minecraft username")
public final String username;
@NotEmpty(message = "You have to provide an e-mail address")
@Email(regexp = "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)])",
message = "This is not a valid e-mail address")
public final String email;
@Length(min = 11, max = 2000, message = "Your question should have between 10 and 2000 characters")
public final String question;
@Override
public String toString() {
return "ContactFormData{" +
"username='" + username + '\'' +
", email='" + email + '\'' +
", question='" + question + '\'' +
'}';
}
@Override
public MessageEmbed toMessageEmbed() {
return new EmbedBuilder()
.addField("Username", username, false)
.addField("email", email, false)
.appendDescription(question)
.setColor(Color.GREEN)
.build();
}
}
@@ -0,0 +1,11 @@
package com.alttd.communication.formData;
import net.dv8tion.jda.api.entities.MessageEmbed;
public abstract class Form {
@Override
public abstract String toString();
public abstract MessageEmbed toMessageEmbed();
}
@@ -27,7 +27,7 @@ public abstract class AbstractConfig {
private ConfigurationNode config;
protected AbstractConfig(String filename) {
init(new File(new File(AltitudeBot.getInstance().getDataFolder()).getParentFile(), filename), filename);
init(new File(new File(AltitudeBot.getInstance().getDataFolder()), filename), filename);
}
private void init(File file, String filename) {
@@ -18,11 +18,13 @@ public class MessagesConfig extends AbstractConfig {
public static String HELP_SUGGESTION = "`/suggestion`: Opens suggestion form";
public static String HELP_MESSAGE_TEMPLATE = "<commands>";
public static String HELP_SEEN = "<commands>";
public static String HELP_SYNC_NITRO = "Syncs the nitro ranks with the minecraft ranks";
private static void loadHelp() {
HELP_HELP = messagesConfig.getString("help.help", HELP_HELP);
HELP_SUGGESTION = messagesConfig.getString("help.suggestion", HELP_SUGGESTION);
HELP_MESSAGE_TEMPLATE = messagesConfig.getString("help.message-template", HELP_MESSAGE_TEMPLATE);
HELP_SEEN = messagesConfig.getString("help.seen", HELP_SEEN);
HELP_SYNC_NITRO = messagesConfig.getString("help.sync-alpha", HELP_SYNC_NITRO);
}
private static void loadPollHelp() {
@@ -1,5 +1,6 @@
package com.alttd.contextMenuManager;
import com.alttd.contextMenuManager.contextMenus.ContextMenuCreateEvent;
import com.alttd.contextMenuManager.contextMenus.ContextMenuForwardToKanboard;
import com.alttd.contextMenuManager.contextMenus.ContextMenuRespondSuggestion;
import com.alttd.modalManager.ModalManager;
@@ -23,6 +24,7 @@ public class ContextMenuManager extends ListenerAdapter {
public ContextMenuManager(ModalManager modalManager) {
contextMenus = List.of(
new ContextMenuRespondSuggestion(modalManager),
new ContextMenuCreateEvent(modalManager),
new ContextMenuForwardToKanboard()
);
}
@@ -0,0 +1,69 @@
package com.alttd.contextMenuManager.contextMenus;
import com.alttd.contextMenuManager.DiscordContextMenu;
import com.alttd.modalManager.ModalManager;
import com.alttd.modalManager.modals.ModalCreateEvent;
import com.alttd.util.Util;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
public class ContextMenuCreateEvent extends DiscordContextMenu {
private final ModalManager modalManager;
public ContextMenuCreateEvent(ModalManager modalManager) {
this.modalManager = modalManager;
}
@Override
public String getContextMenuId() {
return "Create Event";
}
@Override
public void execute(UserContextInteractionEvent event) {
event.getInteraction().replyEmbeds(Util.genericErrorEmbed("Error", "This interaction should have been a message interaction"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
@Override
public void execute(MessageContextInteractionEvent event) {
if (!event.isFromGuild()) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This has to be done in a guild"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
Message message = event.getInteraction().getTarget();
if (message.getChannel().getIdLong() != 1172922338023591956L || message.getAuthor().getIdLong() != event.getUser().getIdLong()) {
event.getInteraction().replyEmbeds(Util.genericErrorEmbed("Error", "You can only use this on your own community post"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
Modal createEvent = modalManager.getModalFor("create_event");
if (createEvent == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find create event modal"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
ModalCreateEvent.userToMessageTracker.putMessage(event.getUser().getIdLong(), message); //TODO find a better way to do this
event.replyModal(createEvent).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
@Override
public CommandData getUserContextInteraction() {
return Commands.message(getContextMenuId())
.setContexts(InteractionContextType.GUILD)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MESSAGE_SEND));
}
}
@@ -7,6 +7,7 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
@@ -46,7 +47,7 @@ public class ContextMenuForwardToKanboard extends DiscordContextMenu {
@Override
public CommandData getUserContextInteraction() {
return Commands.message(getContextMenuId())
.setGuildOnly(true)
.setContexts(InteractionContextType.GUILD)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR));
}
}
@@ -15,10 +15,11 @@ import net.dv8tion.jda.api.entities.channel.unions.IThreadContainerUnion;
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionContextType;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
public class ContextMenuRespondSuggestion extends DiscordContextMenu {
@@ -56,14 +57,14 @@ public class ContextMenuRespondSuggestion extends DiscordContextMenu {
return;
}
ModalReplySuggestion.putMessage(event.getUser().getIdLong(), message); //TODO find a better way to do this
ModalReplySuggestion.userToMessageTracker.putMessage(event.getUser().getIdLong(), message); //TODO find a better way to do this
event.replyModal(replySuggestion).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
@Override
public CommandData getUserContextInteraction() {
return Commands.message(getContextMenuId())
.setGuildOnly(true)
.setContexts(InteractionContextType.GUILD)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR));
}
@@ -176,6 +176,39 @@ public class DatabaseTables {
}
}
private void createSettingsTable() {
String sql = "CREATE TABLE IF NOT EXISTS settings(" +
"name VARCHAR(32) NOT NULL, " +
"value VARCHAR(64) NOT NULL, " +
"type VARCHAR(16) NOT NULL, " +
"PRIMARY KEY (name)" +
")";
try {
connection.prepareStatement(sql).executeUpdate();
} catch (SQLException e) {
Logger.altitudeLogs.error(e);
Logger.altitudeLogs.error("Unable to create auction settings table, shutting down...");
}
}
private void createEventsTable() {
String sql = "CREATE TABLE IF NOT EXISTS events(" +
"message_id BIGINT NOT NULL, " +
"channel_id BIGINT NOT NULL, " +
"guild_id BIGINT NOT NULL, " +
"epoch_second BIGINT NOT NULL, " +
"role_id BIGINT NOT NULL," +
"title VARCHAR(128) NOT NULL, " +
"PRIMARY KEY (message_id)" +
")";
try {
connection.prepareStatement(sql).executeUpdate();
} catch (SQLException e) {
Logger.altitudeLogs.error(e);
Logger.altitudeLogs.error("Unable to create auction settings table, shutting down...");
}
}
public static void createTables(Connection connection) {
if (instance == null)
instance = new DatabaseTables(connection);
@@ -6,15 +6,14 @@ import com.alttd.database.queries.QueriesAuctionActions.QueriesAuctionAction;
import com.alttd.selectMenuManager.DiscordSelectMenu;
import com.alttd.selectMenuManager.SelectMenuManager;
import com.alttd.util.Util;
import net.dv8tion.jda.api.components.selections.SelectMenu;
import net.dv8tion.jda.api.components.selections.SelectOption;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -1,12 +1,15 @@
package com.alttd.database.queries.QueriesReminders;
import com.alttd.util.Logger;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.Channel;
import org.jspecify.annotations.NonNull;
import java.util.Arrays;
import java.util.Optional;
@Slf4j
public record Reminder (int id, String title, String description, long userId, long guildId, long channelId,
long messageId, boolean shouldRepeat, long creationDate, long remindDate, ReminderType reminderType, byte[] data) {
@@ -26,34 +29,35 @@ public record Reminder (int id, String title, String description, long userId, l
reminder.data());
}
public Channel getChannel(JDA jda) {
Guild guildById = getGuild(jda);
if (guildById == null)
return null;
public Optional<Channel> getChannel(JDA jda) {
Optional<Guild> optionalGuild = getGuild(jda);
if (optionalGuild.isEmpty())
return Optional.empty();
Channel channelById = guildById.getTextChannelById(this.channelId);
Guild guild = optionalGuild.get();
Channel channelById = guild.getTextChannelById(this.channelId);
if (channelById == null)
channelById = guildById.getThreadChannelById(this.channelId);
channelById = guild.getThreadChannelById(this.channelId);
if (channelById == null) {
Logger.altitudeLogs.warning("Unable to find text channel for reminder, text channel id: [" + channelId + "]");
return null;
log.warn("Unable to find text channel for reminder, text channel id: [{}]", channelId);
return Optional.empty();
}
return channelById;
return Optional.of(channelById);
}
public Guild getGuild(JDA jda) {
public Optional<Guild> getGuild(JDA jda) {
Guild guildById = jda.getGuildById(guildId);
if (guildById == null) {
Logger.altitudeLogs.warning("Unable to find guild for reminder, guild id: [" + guildId + "]");
return null;
log.warn("Unable to find guild for reminder, guild id: [{}]", guildId);
return Optional.empty();
}
return guildById;
return Optional.of(guildById);
}
@Override
public String toString() {
public @NonNull String toString() {
return "Reminder{" +
"\nid=[" + id + "]" +
"\ntitle=[" + title + "]" +
@@ -0,0 +1,64 @@
package com.alttd.database.queries;
import com.alttd.DTO.JoinDate;
import com.alttd.database.Database;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class QueriesStaffJoinDate {
public static Optional<JoinDate> getJoinDate(long userId) {
String sql = "SELECT date FROM staff_join_date WHERE user_id = ?";
try (PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql)) {
preparedStatement.setLong(1, userId);
ResultSet resultSet = preparedStatement.executeQuery();
if (!resultSet.next())
return Optional.empty();
Instant date = Instant.ofEpochMilli(resultSet.getLong("date"));
if (date == null) {
return Optional.empty();
}
return Optional.of(new JoinDate(userId, date));
} catch (SQLException exception) {
exception.printStackTrace();
return Optional.empty();
}
}
public static void setJoinDate(long userId, Instant date) {
String sql = "INSERT INTO staff_join_date (user_id, date) VALUES (?, ?) ON DUPLICATE KEY UPDATE date = VALUES(date)";
try (PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql)) {
preparedStatement.setLong(1, userId);
preparedStatement.setLong(2, date.toEpochMilli());
preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public static List<JoinDate> getAllJoinDates() {
String sql = "SELECT * FROM staff_join_date";
try (PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql)) {
ResultSet resultSet = preparedStatement.executeQuery();
List<JoinDate> joinDates = new ArrayList<>();
while (resultSet.next())
joinDates.add(new JoinDate(resultSet.getLong("user_id"), Instant.ofEpochMilli(resultSet.getLong("date"))));
return joinDates;
} catch (SQLException exception) {
exception.printStackTrace();
return null;
}
}
}
@@ -0,0 +1,46 @@
package com.alttd.database.queries;
import com.alttd.database.Database;
import com.alttd.util.Logger;
import lombok.extern.slf4j.Slf4j;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Slf4j
public class QueriesUserByRole {
public static CompletableFuture<Optional<List<Long>>> getUserIdsByRole(String role) {
String sql = """
SELECT discord_id
FROM linked_accounts
JOIN account_roles ON linked_accounts.player_uuid = account_roles.uuid
WHERE account_roles.role_name = ?
AND linked_accounts.active = true;
""";
return CompletableFuture.supplyAsync(() -> {
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
preparedStatement.setString(1, role);
ResultSet resultSet = preparedStatement.executeQuery();
List<Long> discordIds = new ArrayList<>();
while (resultSet.next()) {
discordIds.add(resultSet.getLong("discord_id"));
}
return Optional.of(discordIds);
} catch (SQLException exception) {
log.error("Failed to get user ids by role", exception);
Logger.altitudeLogs.error(exception);
}
return Optional.empty();
});
}
}
@@ -2,6 +2,7 @@ package com.alttd.database.queries;
import com.alttd.database.Database;
import com.alttd.util.Logger;
import net.dv8tion.jda.api.entities.Member;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -13,7 +14,7 @@ import java.util.concurrent.CompletableFuture;
public class QueriesUserDiscordId {
public static CompletableFuture<Optional<UUID>> getUUIDById(long userId) {
String sql = "SELECT player_uuid FROM linked_accounts WHERE discord_id = ?";
String sql = "SELECT player_uuid FROM linked_accounts WHERE discord_id = ? AND active = true";
return CompletableFuture.supplyAsync(() -> {
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
@@ -30,5 +31,64 @@ public class QueriesUserDiscordId {
});
}
public static CompletableFuture<Void> removeLinkedUserByDiscordId(long userId) {
String sql = "UPDATE linked_accounts SET active = false WHERE discord_id = ?";
return CompletableFuture.runAsync(() -> {
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
preparedStatement.setLong(1, userId);
preparedStatement.executeUpdate();
} catch (SQLException exception) {
Logger.altitudeLogs.error(exception);
}
});
}
public static CompletableFuture<Void> removeRole(long userId, String role) {
String sql = """
DELETE FROM account_roles
WHERE uuid IN (
SELECT player_uuid
FROM linked_accounts
WHERE discord_id = ?
)
AND role_name = ?
""";
return CompletableFuture.runAsync(() -> {
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
preparedStatement.setLong(1, userId);
preparedStatement.setString(2, role);
preparedStatement.executeUpdate();
} catch (SQLException exception) {
Logger.altitudeLogs.error(exception);
}
});
}
public static CompletableFuture<Void> addRoleIfMissing(long userId, String role) {
String sql = """
INSERT INTO account_roles (uuid, role_name)
SELECT player_uuid, ?
FROM linked_accounts
WHERE discord_id = ?
AND NOT EXISTS (
SELECT 1
FROM account_roles
WHERE uuid = player_uuid
AND role_name = ?)
""";
return CompletableFuture.runAsync(() -> {
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
preparedStatement.setString(1, role);
preparedStatement.setLong(2, userId);
preparedStatement.setString(3, role);
preparedStatement.executeUpdate();
} catch (SQLException exception) {
Logger.altitudeLogs.error(exception);
}
});
}
}
@@ -0,0 +1,79 @@
package com.alttd.database.queries.events;
import com.alttd.AltitudeBot;
import com.alttd.util.Logger;
import lombok.Getter;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import java.time.Instant;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Optional;
public final class Event {
private static final HashMap<Long, Event> eventMap = new HashMap<>();
@Getter
private final long messageId, guildId, channelId, roleId;
@Getter
private final Instant startTime;
@Getter
private Role role = null;
@Getter
private final String title;
public static Event getEvent(long messageId) {
return eventMap.get(messageId);
}
private Message message = null;
public Event(long messageId, long guildId, long channelId, Instant startTime, long roleId, String title) {
this.messageId = messageId;
this.guildId = guildId;
this.channelId = channelId;
this.startTime = startTime;
this.roleId = roleId;
this.title = title;
eventMap.put(messageId, this);
loadMessageAndRole();
Logger.altitudeLogs.info(String.format("Loaded event with title [%s] and message id [%s]", title, messageId));
}
public static Optional<Event> getNextEvent() {
return eventMap.values().stream().min(Comparator.comparing(Event::getStartTime));
}
public static void removeEvent(Event event) {
eventMap.remove(event.getMessageId());
}
private void loadMessageAndRole() {
Guild guild = AltitudeBot.getInstance().getJDA().getGuildById(guildId);
if (guild == null) {
Logger.altitudeLogs.error(String.format("Unable to find guild %s when creating event", guildId));
return;
}
TextChannel textChannel = guild.getTextChannelById(channelId);
if (textChannel == null) {
Logger.altitudeLogs.error(String.format("Unable to find text channel %s when creating event", channelId));
return;
}
textChannel.retrieveMessageById(messageId).queue(message -> {
this.message = message;
Logger.altitudeLogs.debug(String.format("Loaded message for event with title [%s]", title));
});
role = guild.getRoleById(roleId);
}
public Optional<Message> getMessage() {
return message == null ? Optional.empty() : Optional.of(message);
}
};
@@ -0,0 +1,59 @@
package com.alttd.database.queries.events;
import com.alttd.database.Database;
import com.alttd.util.Logger;
import net.dv8tion.jda.api.entities.Message;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.Instant;
public class QueriesEvent {
public void addEvent(Message message, Instant start, long roleId, String title) {
String sql = "INSERT INTO events VALUES(?, ?, ?, ?, ?, ?)";
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
preparedStatement.setLong(1, message.getIdLong());
preparedStatement.setLong(2, message.getChannelIdLong());
preparedStatement.setLong(3, message.getGuildIdLong());
preparedStatement.setLong(4, start.getEpochSecond());
preparedStatement.setLong(5, roleId);
preparedStatement.setString(6, title);
preparedStatement.executeUpdate();
} catch (SQLException exception) {
Logger.altitudeLogs.error(exception);
}
}
public void loadActiveEvents() {
String sql = "SELECT * FROM events WHERE epoch_second > ?";
int counter = 0;
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
preparedStatement.setLong(1, Instant.now().getEpochSecond());
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
new Event(
resultSet.getLong("message_id"),
resultSet.getLong("guild_id"),
resultSet.getLong("channel_id"),
Instant.ofEpochSecond(resultSet.getLong("epoch_second")),
resultSet.getLong("role_id"),
resultSet.getString("title")
);
counter++;
}
} catch (SQLException exception) {
Logger.altitudeLogs.error(exception);
}
Logger.altitudeLogs.info(String.format("Loaded %d events", counter));
}
}
@@ -0,0 +1,4 @@
package com.alttd.database.queries.settings;
public class QueriesSettings {
}
@@ -0,0 +1,59 @@
package com.alttd.database.queries.settings;
import com.alttd.database.Database;
import java.sql.*;
import java.util.List;
import java.util.stream.Collectors;
public class Setting {
private final List<Class> allowedClasses = List.of(Boolean.class, Integer.class, Long.class, Float.class, Double.class, String.class);
public <T> void insertSetting(String key, T value, String type) throws SQLException, IllegalArgumentException {
if (!allowedClasses.contains(type)) {
throw new IllegalArgumentException(String.format("Invalid type, the only allowed types are: %s", allowedClasses.stream().map(Class::getSimpleName).collect(Collectors.joining(", "))));
}
String query = "INSERT INTO settings (name, value, type) VALUES (?, ?, ?)";
try (Connection connection = DriverManager.getConnection("your_connection_string");
PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, key);
preparedStatement.setString(2, value.toString());
preparedStatement.setString(3, type);
preparedStatement.executeUpdate();
}
}
public <T> T getSetting(String key, Class<T> type) throws SQLException, IllegalArgumentException {
if (!allowedClasses.contains(type)) {
throw new IllegalArgumentException(String.format("Invalid type, the only allowed types are: %s", allowedClasses.stream().map(Class::getSimpleName).collect(Collectors.joining(", "))));
}
String query = "SELECT value, type FROM settings WHERE name = ?";
try (Connection connection = Database.getDatabase().getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(query)) {
preparedStatement.setString(1, key);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
String dbType = resultSet.getString("type");
if (!dbType.equals(type.getSimpleName())) {
throw new IllegalArgumentException(String.format("%s is of type %s not %s", key, dbType, type.getSimpleName()));
}
String value = resultSet.getString("value");
if (type.equals(Integer.class)) {
return type.cast(Integer.parseInt(value));
} else if (type.equals(Boolean.class)) {
return type.cast(Boolean.parseBoolean(value));
} // and so on for other types
else {
return type.cast(value);
}
}
}
throw new SQLException("Key not found in settings");
}
}
@@ -8,6 +8,8 @@ import com.alttd.database.queries.QueriesReminders.ReminderType;
import com.alttd.schedulers.ReminderScheduler;
import com.alttd.util.Logger;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
@@ -15,7 +17,6 @@ import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
@@ -47,15 +48,15 @@ public class AppealRepost extends ListenerAdapter {
}
Message message = event.getMessage();
List<MessageEmbed> embeds = message.getEmbeds();
if (embeds.size() == 0) {
if (embeds.isEmpty()) {
return;
}
MessageEmbed messageEmbed = embeds.get(0);
MessageEmbed messageEmbed = embeds.getFirst();
List<MessageEmbed.Field> fields = messageEmbed.getFields();
if (fields.size() == 0) {
if (fields.isEmpty()) {
return;
}
String name = fields.get(0).getName();
String name = fields.getFirst().getName();
if (name == null || !name.equals("Punishment info")) {
return;
}
@@ -89,7 +90,7 @@ public class AppealRepost extends ListenerAdapter {
return;
}
message.getChannel().sendMessageEmbeds(embed).queue(res -> {
res.editMessageComponents().setActionRow(reminderAccepted, reminderInProgress, reminderDenied).queue();
res.editMessageComponents(ActionRow.of(reminderAccepted, reminderInProgress, reminderDenied)).queue();
res.createThreadChannel("Appeal").queue((
threadChannel -> {
scheduleReminder(res, member, threadChannel);
@@ -0,0 +1,22 @@
package com.alttd.listeners;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NonNls;
import java.util.List;
public class AutoThread extends ListenerAdapter {
List<Long> channels = List.of(1172922338023591956L);
@Override
public void onMessageReceived(@NonNls MessageReceivedEvent event) {
if (!channels.contains(event.getChannel().getIdLong())) {
return;
}
event.getMessage().createThreadChannel("Auto Thread").queue(threadChannel ->
threadChannel.sendMessage("Thread for community post by: " + event.getAuthor().getAsMention())
.queue());
}
}
@@ -1,11 +1,14 @@
package com.alttd.listeners;
import com.alttd.AltitudeBot;
import com.alttd.buttonManager.ButtonManager;
import com.alttd.commandManager.CommandManager;
import com.alttd.contextMenuManager.ContextMenuManager;
import com.alttd.database.queries.Poll.PollQueries;
import com.alttd.database.queries.events.QueriesEvent;
import com.alttd.modalManager.ModalManager;
import com.alttd.schedulers.AuctionScheduler;
import com.alttd.schedulers.EventTimerTask;
import com.alttd.schedulers.PollTimerTask;
import com.alttd.schedulers.ReminderScheduler;
import com.alttd.request.RequestManager;
@@ -19,6 +22,7 @@ import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.GenericSelectMenuInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.SpringApplication;
import java.util.Timer;
import java.util.concurrent.TimeUnit;
@@ -26,9 +30,11 @@ import java.util.concurrent.TimeUnit;
public class JDAListener extends ListenerAdapter {
private final JDA jda;
private final String[] args;
public JDAListener(JDA jda) {
public JDAListener(JDA jda, String[] args) {
this.jda = jda;
this.args = args;
}
@Override
@@ -36,17 +42,23 @@ public class JDAListener extends ListenerAdapter {
Logger.altitudeLogs.info("JDA ready to register commands.");
LockedChannel lockedChannel = new LockedChannel();
ButtonManager buttonManager = new ButtonManager();
AutoThread autoThread = new AutoThread();
TagAdded tagAdded = new TagAdded();
AppealRepost appealRepost = new AppealRepost(buttonManager);
ModalManager modalManager = new ModalManager(buttonManager);
ContextMenuManager contextMenuManager = new ContextMenuManager(modalManager);
SelectMenuManager selectMenuManager = new SelectMenuManager();
CommandManager commandManager = new CommandManager(jda, modalManager, contextMenuManager, lockedChannel, selectMenuManager, buttonManager);
jda.addEventListener(buttonManager, tagAdded, modalManager, commandManager, contextMenuManager, lockedChannel, appealRepost, selectMenuManager);
jda.addEventListener(buttonManager, tagAdded, modalManager, commandManager, contextMenuManager, lockedChannel,
appealRepost, selectMenuManager, autoThread);
PollQueries.loadPolls(buttonManager);
new Timer().scheduleAtFixedRate(new PollTimerTask(jda, Logger.altitudeLogs), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(5));
new QueriesEvent().loadActiveEvents();
new Timer().scheduleAtFixedRate(new EventTimerTask(), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1));
startSchedulers();
// RequestManager.init();
// Logger.altitudeLogs.info("Starting spring application");
// SpringApplication.run(AltitudeBot.class, args);
}
private void startSchedulers() {
@@ -1,7 +1,7 @@
package com.alttd.modalManager;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.modals.Modal;
public abstract class DiscordModal {
@@ -2,16 +2,12 @@ package com.alttd.modalManager;
import com.alttd.buttonManager.ButtonManager;
import com.alttd.modalManager.modals.*;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.modals.Modal;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.List;
import java.util.Optional;
@@ -25,7 +21,8 @@ public class ModalManager extends ListenerAdapter {
new ModalEvidence(),
new ModalReplySuggestion(),
new ModalRemindMe(buttonManager),
new ModalCrateItem());
new ModalCrateItem(),
new ModalCreateEvent(buttonManager));
}
@Override
@@ -51,8 +48,6 @@ public class ModalManager extends ListenerAdapter {
Optional<DiscordModal> first = modals.stream()
.filter(discordModal -> discordModal.getModalId().equalsIgnoreCase(modalId))
.findFirst();
if (first.isEmpty())
return null;
return first.get().getModal();
return first.map(DiscordModal::getModal).orElse(null);
}
}
@@ -5,17 +5,17 @@ import com.alttd.database.queries.commandOutputChannels.OutputType;
import com.alttd.modalManager.DiscordModal;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.label.Label;
import net.dv8tion.jda.api.components.textinput.TextInput;
import net.dv8tion.jda.api.components.textinput.TextInputStyle;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.interactions.modals.ModalMapping;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import java.awt.*;
@@ -88,38 +88,42 @@ public class ModalCrateItem extends DiscordModal {
@Override
public Modal getModal() {
TextInput item = TextInput.create("item", "Item", TextInputStyle.SHORT)
TextInput item = TextInput.create("item", TextInputStyle.SHORT)
.setPlaceholder("Bone")
.setRequiredRange(1, 32)
.setRequired(true)
.build();
TextInput itemName = TextInput.create("item_name", "Item Name", TextInputStyle.SHORT)
TextInput itemName = TextInput.create("item_name", TextInputStyle.SHORT)
.setPlaceholder("Scruff's Bone")
.setRequiredRange(1, 32)
.setRequired(true)
.build();
TextInput lore = TextInput.create("lore", "Lore", TextInputStyle.PARAGRAPH)
TextInput lore = TextInput.create("lore", TextInputStyle.PARAGRAPH)
.setPlaceholder("A bone owned by the Altitude Mascot")
.setRequiredRange(1, 256)
.setRequired(true)
.build();
TextInput enchants = TextInput.create("enchants", "Enchants", TextInputStyle.PARAGRAPH)
TextInput enchants = TextInput.create("enchants", TextInputStyle.PARAGRAPH)
.setPlaceholder("Unbreaking 1")
.setRequiredRange(1, 256)
.setRequired(false)
.build();
TextInput explanation = TextInput.create("explanation", "The explanation behind your item", TextInputStyle.PARAGRAPH)
TextInput explanation = TextInput.create("explanation", TextInputStyle.PARAGRAPH)
.setPlaceholder("Scruff loves strong bones")
.setRequiredRange(1, 2000)
.setRequired(false)
.build();
return Modal.create(getModalId(), "Crate Item Suggestion")
.addActionRows(ActionRow.of(item), ActionRow.of(itemName), ActionRow.of(lore), ActionRow.of(enchants), ActionRow.of(explanation))
.addComponents(Label.of("Item", item))
.addComponents(Label.of("Item name", itemName))
.addComponents(Label.of("Lore", lore))
.addComponents(Label.of("Enchants", enchants))
.addComponents(Label.of("The explanation behind your item", explanation))
.build();
}
@@ -0,0 +1,157 @@
package com.alttd.modalManager.modals;
import com.alttd.buttonManager.ButtonManager;
import com.alttd.database.queries.events.Event;
import com.alttd.database.queries.events.QueriesEvent;
import com.alttd.modalManager.DiscordModal;
import com.alttd.util.UserToMessageTracker;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.components.label.Label;
import net.dv8tion.jda.api.components.textinput.TextInput;
import net.dv8tion.jda.api.components.textinput.TextInputStyle;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.interactions.modals.ModalMapping;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.RoleAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import java.awt.*;
import java.time.Instant;
import java.util.Random;
import java.util.stream.Collectors;
public class ModalCreateEvent extends DiscordModal {
public static final UserToMessageTracker userToMessageTracker = new UserToMessageTracker();
private final ButtonManager buttonManager;
public ModalCreateEvent(ButtonManager buttonManager) {
this.buttonManager = buttonManager;
}
@Override
public String getModalId() {
return "create_event";
}
@Override
public void execute(ModalInteractionEvent event) {
ModalMapping titleModalMapping = event.getInteraction().getValue("title");
ModalMapping timeModalMapping = event.getInteraction().getValue("time");
if (titleModalMapping == null || timeModalMapping == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find time or title in modal"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
String title = titleModalMapping.getAsString();
String time = timeModalMapping.getAsString();
if (title.isEmpty() || time.isEmpty()) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Response in modal is empty"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
Instant eventStart;
try {
eventStart = Instant.ofEpochSecond(Long.parseLong(time));
} catch (NumberFormatException e) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid time format, try again"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
Member member = event.getMember();
if (member == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This modal only works from within a guild"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
Message message = userToMessageTracker.pullMessage(member.getIdLong());
if (message == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "No message found to create an event from"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
MessageEmbed messageEmbed = new EmbedBuilder()
.setTitle(title)
.addField("Event Start", "<t:" + time + ":F>", true)
.addField("Participants", "0", true)
.setFooter("Click the join button to be notified when the event starts")
.setColor(Color.GREEN)
.build();
Button eventButton = buttonManager.getButtonFor("event_button");
if (eventButton == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find event button"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
try (MessageCreateData build = new MessageCreateBuilder()
.setEmbeds(messageEmbed)
.setComponents(ActionRow.of(eventButton))
.build()) {
Guild guild = message.getGuild();
ReplyCallbackAction replyCallbackAction = event.deferReply(true);
createRole(guild).queue(role -> {
message.reply(build).queue(newMessage -> {
new QueriesEvent().addEvent(newMessage, eventStart, role.getIdLong(), title);
new Event(newMessage.getIdLong(), newMessage.getGuildIdLong(), newMessage.getChannelIdLong(), eventStart, role.getIdLong(), title);
});
replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "Your event has been created")).queue();
}, failed -> {
replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "Unable to create event")).queue();
});
}
}
private RoleAction createRole(Guild guild) {
String possibleCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random rand = new Random();
String randomStr = rand.ints(5, 0, possibleCharacters.length())
.mapToObj(i -> possibleCharacters.charAt(i) + "")
.collect(Collectors.joining());
return guild.createRole().setName("event role " + randomStr)
.setMentionable(false)
.setHoisted(false);
}
@Override
public Modal getModal() {
String currentTimestamp = String.valueOf(Instant.now().getEpochSecond());
TextInput time = TextInput.create("time", TextInputStyle.SHORT)
.setValue("Epoch time, see https://epochconverter.com/")
.setPlaceholder(currentTimestamp)
.setMinLength(currentTimestamp.length())
.setMaxLength(currentTimestamp.length() + 1)
.setRequired(true)
.build();
TextInput title = TextInput.create("title", TextInputStyle.SHORT)
.setPlaceholder("The title for your event")
.setMinLength(5)
.setMaxLength(128)
.setRequired(true)
.build();
return Modal.create(getModalId(), "Create an event")
.addComponents(Label.of("Event title", title), Label.of("time", time))
.build();
}
}
@@ -5,17 +5,17 @@ import com.alttd.database.queries.commandOutputChannels.OutputType;
import com.alttd.modalManager.DiscordModal;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.label.Label;
import net.dv8tion.jda.api.components.textinput.TextInput;
import net.dv8tion.jda.api.components.textinput.TextInputStyle;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.interactions.modals.ModalMapping;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
@@ -86,32 +86,35 @@ public class ModalEvidence extends DiscordModal {
@Override
public Modal getModal() {
TextInput user = TextInput.create("user", "User", TextInputStyle.SHORT)
TextInput user = TextInput.create("user", TextInputStyle.SHORT)
.setPlaceholder("username/id")
.setRequiredRange(1, 256)
.setRequired(true)
.build();
TextInput punishmentType = TextInput.create("punishment-type", "Punishment Type", TextInputStyle.SHORT)
TextInput punishmentType = TextInput.create("punishment-type", TextInputStyle.SHORT)
.setPlaceholder("punishment type")
.setRequiredRange(3, 256)
.setRequired(true)
.build();
TextInput reason = TextInput.create("reason", "Reason", TextInputStyle.SHORT)
TextInput reason = TextInput.create("reason", TextInputStyle.SHORT)
.setPlaceholder("punishment reason")
.setRequiredRange(10, 256)
.setRequired(true)
.build();
TextInput evidence = TextInput.create("evidence", "Evidence", TextInputStyle.PARAGRAPH)
TextInput evidence = TextInput.create("evidence", TextInputStyle.PARAGRAPH)
.setPlaceholder("evidence")
.setRequiredRange(10, 1024)
.setRequired(true)
.build();
return Modal.create(getModalId(), "Evidence")
.addActionRows(ActionRow.of(user), ActionRow.of(punishmentType), ActionRow.of(reason), ActionRow.of(evidence))
.addComponents(Label.of("User", user))
.addComponents(Label.of("Punishment Type", punishmentType))
.addComponents(Label.of("Reason", reason))
.addComponents(Label.of("Evidence", evidence))
.build();
}
}
@@ -7,17 +7,17 @@ import com.alttd.database.queries.QueriesReminders.ReminderType;
import com.alttd.modalManager.DiscordModal;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.components.label.Label;
import net.dv8tion.jda.api.components.textinput.TextInput;
import net.dv8tion.jda.api.components.textinput.TextInputStyle;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.interactions.modals.ModalMapping;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.utils.TimeUtil;
import java.util.Date;
import java.util.HashMap;
@@ -94,7 +94,7 @@ public class ModalRemindMe extends DiscordModal {
event.deferReply().setEphemeral(true).queue(defer -> {
ButtonRemindMeConfirm.putReminder(userId, defer, reminder);
defer.editOriginalEmbeds(messageEmbed).queue(message ->
defer.editOriginalComponents().setActionRow(remindMeConfirm, remindMeCancel)
defer.editOriginalComponents(ActionRow.of(remindMeConfirm, remindMeCancel))
.queue(RestAction.getDefaultSuccess(), Util::handleFailure));
});
}
@@ -119,20 +119,22 @@ public class ModalRemindMe extends DiscordModal {
@Override
public Modal getModal() {
TextInput title = TextInput.create("title", "Title", TextInputStyle.SHORT)
TextInput title = TextInput.create("title", TextInputStyle.SHORT)
.setValue("Title")
.setPlaceholder("reminder title")
.setRequiredRange(1, 256)
.setRequired(true)
.build();
TextInput desc = TextInput.create("description", "Description", TextInputStyle.PARAGRAPH)
TextInput desc = TextInput.create("description", TextInputStyle.PARAGRAPH)
.setPlaceholder("optional reminder description")
.setRequiredRange(1, 4000)
.setRequired(false)
.build();
return Modal.create(getModalId(), "Remind Me")
.addActionRows(ActionRow.of(title), ActionRow.of(desc))
.addComponents(Label.of("Title", title))
.addComponents(Label.of("Description", desc))
.build();
}
@@ -1,30 +1,21 @@
package com.alttd.modalManager.modals;
import com.alttd.modalManager.DiscordModal;
import com.alttd.util.UserToMessageTracker;
import com.alttd.util.Util;
import net.dv8tion.jda.api.components.label.Label;
import net.dv8tion.jda.api.components.textinput.TextInput;
import net.dv8tion.jda.api.components.textinput.TextInputStyle;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.interactions.modals.ModalMapping;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.HashMap;
public class ModalReplySuggestion extends DiscordModal {
private static final HashMap<Long, Message> userToMessageMap = new HashMap<>();
public static synchronized void putMessage(long userId, Message message) {
userToMessageMap.put(userId, message);
}
private static synchronized Message pullMessage(long userId) {
return userToMessageMap.remove(userId);
}
public final static UserToMessageTracker userToMessageTracker = new UserToMessageTracker();
@Override
public String getModalId() {
@@ -54,7 +45,7 @@ public class ModalReplySuggestion extends DiscordModal {
return;
}
Message message = pullMessage(member.getIdLong());
Message message = userToMessageTracker.pullMessage(member.getIdLong());
if (message == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find a message for this modal"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
@@ -77,14 +68,14 @@ public class ModalReplySuggestion extends DiscordModal {
@Override
public Modal getModal() {
TextInput body = TextInput.create("response", "Response", TextInputStyle.PARAGRAPH)
TextInput body = TextInput.create("response", TextInputStyle.PARAGRAPH)
.setPlaceholder("Response...")
.setRequiredRange(10, 1024)
.setRequired(true)
.build();
return Modal.create(getModalId(), "Suggestion Response")
.addActionRows(ActionRow.of(body))
.addComponents(Label.of("Response", body))
.build();
}
}
@@ -6,6 +6,11 @@ import com.alttd.database.queries.commandOutputChannels.OutputType;
import com.alttd.modalManager.DiscordModal;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.components.label.Label;
import net.dv8tion.jda.api.components.textinput.TextInput;
import net.dv8tion.jda.api.components.textinput.TextInputStyle;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
@@ -13,12 +18,8 @@ import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.interactions.modals.ModalMapping;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
@@ -98,7 +99,7 @@ public class ModalSuggestion extends DiscordModal {
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
message.editMessageComponents().setActionRow(suggestionReviewAccept, suggestionReviewDeny).queue(
message.editMessageComponents(ActionRow.of(suggestionReviewAccept, suggestionReviewDeny)).queue(
success -> replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "Your suggestion was submitted for review!"), suggestionToPlayer)
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure),
failure -> replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "Couldn't prepare your suggestion for review."), suggestionToPlayer)
@@ -107,20 +108,21 @@ public class ModalSuggestion extends DiscordModal {
@Override
public Modal getModal() {
TextInput title = TextInput.create("title", "Title", TextInputStyle.SHORT)
TextInput title = TextInput.create("title", TextInputStyle.SHORT)
.setPlaceholder("Your suggestion in one sentence")
.setRequiredRange(10, 100)
.setRequired(true)
.build();
TextInput body = TextInput.create("body", "Body", TextInputStyle.PARAGRAPH)
TextInput body = TextInput.create("body", TextInputStyle.PARAGRAPH)
.setPlaceholder("Suggestion...")
.setRequiredRange(30, 1024)
.setRequired(true)
.build();
return Modal.create(getModalId(), "Suggestion Form")
.addActionRows(ActionRow.of(title), ActionRow.of(body))
.addComponents(Label.of("Title", title))
.addComponents(Label.of("Body", body))
.build();
}
}
+24 -20
View File
@@ -5,14 +5,15 @@ import com.alttd.util.Pair;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.buttons.Button;
import net.dv8tion.jda.api.components.label.Label;
import net.dv8tion.jda.api.components.textinput.TextInput;
import net.dv8tion.jda.api.components.textinput.TextInputStyle;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.modals.Modal;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.modals.Modal;
import net.dv8tion.jda.api.requests.restaction.ThreadChannelAction;
import java.awt.*;
@@ -25,24 +26,26 @@ public class Request {
public Modal modal(Member member) {
TextInput requestTitle = TextInput
.create("title", title, TextInputStyle.SHORT)
.create("title", TextInputStyle.SHORT)
.setPlaceholder(id)
.setRequired(false)
.build();
TextInput requestMessage = TextInput
.create("request", message, TextInputStyle.PARAGRAPH)
.create("request", TextInputStyle.PARAGRAPH)
.build();
return Modal.create("request:" + id, name)
.addActionRow(requestTitle)
.addActionRow(requestMessage)
.addComponents(Label.of(title, requestTitle))
.addComponents(Label.of(message, requestMessage))
.build();
}
public void createThread(Member member, String title, String request) {
TextChannel channel = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID).getTextChannelById(getChannel());
if (title == null || title.isEmpty()) title = id;
if (title == null || title.isEmpty()) {
title = id;
}
String finalTitle = title;
ThreadChannelAction threadChannelAction = channel.createThreadChannel(finalTitle);
threadChannelAction.queue(threadChannel -> {
@@ -54,20 +57,21 @@ public class Request {
}
public void sendEmbed(ThreadChannel channel, String title, String request) {
// Pair<EmbedBuilder, ActionRow> pair = getRequestEmbed(channel.getId(), title, request);
// Pair<EmbedBuilder, ActionRow> pair = getRequestEmbed(channel.getId(), title, request);
// pairs are not really possible here :(
EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setTitle(title)
.addField(getName(), request, false)
.setColor(new Color(41, 43, 47));
channel.sendMessageEmbeds(embedBuilder.build()).queue(message1 ->
channel.editMessageEmbedsById(message1.getId(), embedBuilder.build())
.setActionRow(
Button.primary("request:" + getId() + ":" + channel.getId() + ":" + message1.getId() + ":progress", "in progress"),
Button.success("request:" + getId() + ":" + channel.getId() + ":" + message1.getId() + ":complete", "complete"),
Button.danger("request:" + getId() + ":" + channel.getId() + ":" + message1.getId() + ":denied", "denied")
).queue()
);
channel.sendMessageEmbeds(embedBuilder.build())
.queue(message1 ->
channel.editMessageEmbedsById(message1.getId(), embedBuilder.build())
.queue(message2 -> channel.editMessageComponentsById(message1.getId(), ActionRow.of(
Button.primary("request:" + getId() + ":" + channel.getId() + ":" + message1.getId() + ":progress", "in progress"),
Button.success("request:" + getId() + ":" + channel.getId() + ":" + message1.getId() + ":complete", "complete"),
Button.danger("request:" + getId() + ":" + channel.getId() + ":" + message1.getId() + ":denied", "denied")
)).queue())
);
}
public Pair<EmbedBuilder, ActionRow> getRequestEmbed(String channellId, String title, String request) {
@@ -80,7 +84,7 @@ public class Request {
Button.primary("request:" + getId() + ":" + channellId + ":progress", "in progress"),
Button.success("request:" + getId() + ":" + channellId + ":complete", "complete"),
Button.danger("request:" + getId() + ":" + channellId + ":denied", "denied")
);
);
return new Pair<>(embedBuilder, actionRow);
}
@@ -2,22 +2,28 @@ package com.alttd.request;
import com.alttd.AltitudeBot;
import com.alttd.util.Pair;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.selections.StringSelectMenu;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
import java.awt.*;
@Slf4j
public class RequestManager {
public static void init() {
RequestConfig.reload();
if (RequestConfig.REQUEST_MESSAGE == null || RequestConfig.REQUEST_MESSAGE.isEmpty())
if (RequestConfig.REQUEST_MESSAGE == null || RequestConfig.REQUEST_MESSAGE.isEmpty()) {
sendRequestMessage();
}
}
public static Pair<EmbedBuilder, StringSelectMenu.Builder> getRequestEmbed() {
@@ -36,20 +42,39 @@ public class RequestManager {
}
public static void sendRequestMessage() {
TextChannel channel = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID).getTextChannelById(RequestConfig.REQUEST_CHANNEL);
Guild guildById = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID);
if (guildById == null) {
log.error("Unable to find guild with id {} for sendRequestMessage", RequestConfig.REQUEST_GUILD_ID);
return;
}
TextChannel channel = guildById
.getTextChannelById(RequestConfig.REQUEST_CHANNEL);
if (channel == null) {
log.error("Unable to find channel with id {} for sendRequestMessage", RequestConfig.REQUEST_CHANNEL);
return;
}
Pair<EmbedBuilder, StringSelectMenu.Builder> pair = getRequestEmbed();
channel.sendMessageEmbeds(pair.getValue0().build()).setActionRow(
pair.getValue1().build()
).queue(m -> RequestConfig.setRequestMessage(m.getId()));
channel.sendMessageEmbeds(pair.getValue0().build())
.queue(message -> message.editMessageComponents(ActionRow.of(pair.getValue1().build()))
.queue(m -> RequestConfig.setRequestMessage(m.getId())));
}
public static void updateRequestMessage() {
TextChannel channel = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID).getTextChannelById(RequestConfig.REQUEST_CHANNEL);
Guild guildById = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID);
if (guildById == null) {
log.error("Unable to find guild with id for updateRequestMessage {}", RequestConfig.REQUEST_GUILD_ID);
return;
}
TextChannel channel = guildById
.getTextChannelById(RequestConfig.REQUEST_CHANNEL);
if (channel == null) {
log.error("Unable to find channel with id {} for updateRequestMessage", RequestConfig.REQUEST_CHANNEL);
return;
}
Pair<EmbedBuilder, StringSelectMenu.Builder> pair = getRequestEmbed();
channel.editMessageEmbedsById(RequestConfig.REQUEST_MESSAGE, pair.getValue0().build())
.setActionRow(
pair.getValue1().build()
).queue(m -> RequestConfig.setRequestMessage(m.getId()));
.queue(m -> m.editMessageComponents(ActionRow.of(pair.getValue1().build()))
.queue(m2 -> RequestConfig.setRequestMessage(m2.getId())));
}
public static Request getRequestById(String id) {
@@ -59,7 +84,7 @@ public class RequestManager {
public static void onStringSelectInteraction(StringSelectInteractionEvent event) {
String[] actions = event.getComponentId().split(":");
if (actions[1].equals("create")) {
String[] selection = event.getSelectedOptions().get(0).getValue().split(":");
String[] selection = event.getSelectedOptions().getFirst().getValue().split(":");
if (selection[0].equals("request") && selection[1].equals("open")) {
String id = selection[2];
event.replyModal(getRequestById(id).modal(event.getMember())).queue();
@@ -88,15 +113,43 @@ public class RequestManager {
case "denied" -> {
// TODO open a new modal to input a reason?
// could also do this by command?
event.reply("This request has been denied by " + event.getMember().getAsMention()).queue();
ThreadChannel threadChannel = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID).getThreadChannelById(threadId);
Member member = event.getMember();
if (member == null) {
event.reply("This request has been denied by an unknown member").queue();
} else {
event.reply("This request has been denied by " + member.getAsMention()).queue();
}
Guild guildById = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID);
if (guildById == null) {
log.error("Unable to find guild with id {} for denied", RequestConfig.REQUEST_GUILD_ID);
return;
}
ThreadChannel threadChannel = guildById.getThreadChannelById(threadId);
if (threadChannel == null) {
log.error("Unable to find thread channel with id {} for denied", threadId);
return;
}
threadChannel.getManager().setArchived(true).setLocked(true).queue();
}
case "complete" -> {
// TODO open a new modal to input a reason?
// could also do this by command?
event.reply("This request has been completed by " + event.getMember().getAsMention()).queue();
ThreadChannel threadChannel = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID).getThreadChannelById(threadId);
Member member = event.getMember();
if (member == null) {
event.reply("This request has been completed by an unknown member").queue();
} else {
event.reply("This request has been completed by " + member.getAsMention()).queue();
}
Guild guildById = AltitudeBot.getInstance().getJDA().getGuildById(RequestConfig.REQUEST_GUILD_ID);
if (guildById == null) {
log.error("Unable to find guild with id {} for complete", RequestConfig.REQUEST_GUILD_ID);
return;
}
ThreadChannel threadChannel = guildById.getThreadChannelById(threadId);
if (threadChannel == null) {
log.error("Unable to find thread channel with id {} for complete", threadId);
return;
}
threadChannel.getManager().setArchived(true).setLocked(true).queue();
}
case "progress" -> {
@@ -0,0 +1,45 @@
package com.alttd.schedulers;
import com.alttd.database.queries.events.Event;
import com.alttd.util.Logger;
import net.dv8tion.jda.api.entities.Message;
import java.time.Instant;
import java.util.Optional;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
public class EventTimerTask extends TimerTask {
@Override
public void run() {
checkShouldStartEvent();
}
private void checkShouldStartEvent(){
Optional<Event> nextEvent = Event.getNextEvent();
if (nextEvent.isEmpty()) {
return;
}
Event event = nextEvent.get();
if (event.getStartTime().isAfter(Instant.now())) {
return;
}
Event.removeEvent(event);
performEventAction(event);
event.getRole().delete().queueAfter(1, TimeUnit.HOURS);
checkShouldStartEvent();
}
private void performEventAction(Event event) {
Optional<Message> optionalMessage = event.getMessage();
if (optionalMessage.isEmpty()) {
Logger.altitudeLogs.error("Unable to find message for event");
return;
}
Message message = optionalMessage.get();
message.reply(String.format("%s [%s] is starting!", event.getRole().getAsMention(), event.getTitle())).queue();
}
}
@@ -4,6 +4,7 @@ import com.alttd.database.queries.QueriesReminders.QueriesReminders;
import com.alttd.database.queries.QueriesReminders.Reminder;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
@@ -20,10 +21,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
public class ReminderScheduler {
private static ReminderScheduler instance = null;
@@ -41,10 +44,11 @@ public class ReminderScheduler {
return;
}
reminders.sort(Comparator.comparingLong(Reminder::remindDate));
if (reminders.size() == 0)
if (reminders.isEmpty()) {
nextReminder = null;
else
nextReminder = reminders.get(0);
} else {
nextReminder = reminders.getFirst();
}
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleWithFixedDelay(new ReminderRun(), 0, 1, TimeUnit.MINUTES);
@@ -63,19 +67,22 @@ public class ReminderScheduler {
}
reminders.add(reminder);
reminders.sort(Comparator.comparingLong(Reminder::remindDate));
nextReminder = reminders.get(0);
nextReminder = reminders.getFirst();
}
public synchronized void removeReminder(Reminder reminder, boolean removeFromDatabase) {
Logger.altitudeLogs.debug("Removing reminder with messageId: " + reminder.messageId());
reminders.remove(reminder);
reminders.sort(Comparator.comparingLong(Reminder::remindDate));
if (reminders.size() == 0)
if (reminders.isEmpty()) {
nextReminder = null;
else
nextReminder = reminders.get(0);
if (removeFromDatabase)
QueriesReminders.removeReminder(reminder);
} else {
nextReminder = reminders.getFirst();
}
if (!removeFromDatabase) {
return;
}
QueriesReminders.removeReminder(reminder);
}
public synchronized void removeReminder(long messageId) {
@@ -92,13 +99,14 @@ public class ReminderScheduler {
public void run() {
long time = System.currentTimeMillis();
while (nextReminder != null && time > nextReminder.remindDate()) {
Channel channel = nextReminder.getChannel(jda);
if (channel == null) {
Optional<Channel> optionalChannel = nextReminder.getChannel(jda);
if (optionalChannel.isEmpty()) {
Logger.altitudeLogs.warning("Couldn't find channel, unable to run reminder: " + nextReminder.id() +
"\ntitle: [" + nextReminder.title() +
"]\ndescription: [" + nextReminder.description() + "]");
return;
}
Channel channel = optionalChannel.get();
sendEmbed(nextReminder, channel);
if (nextReminder.shouldRepeat()) {
Reminder repeatedReminder = new Reminder(
@@ -127,31 +135,38 @@ public class ReminderScheduler {
.setTitle(reminder.title())
.setDescription(reminder.description())
.appendDescription("\n\nRequested <t:" + TimeUnit.MILLISECONDS.toSeconds(reminder.creationDate()) + ":R>");
Guild guild = reminder.getGuild(jda);
if (guild == null) {
Optional<Guild> optionalGuild = reminder.getGuild(jda);
if (optionalGuild.isEmpty()) {
sendEmbed(reminder, channel, embedBuilder);
return;
}
Guild guild = optionalGuild.get();
guild.retrieveMemberById(reminder.userId()).queue(
member -> sendEmbed(reminder, channel, embedBuilder, member),
failed -> sendEmbed(reminder, channel, embedBuilder));
}
private MessageCreateAction getCreateAction(Channel channel, EmbedBuilder embedBuilder) {
switch (channel.getType()) {
private Optional<MessageCreateAction> getCreateAction(Channel channel, EmbedBuilder embedBuilder) {
return switch (channel.getType()) {
case TEXT, NEWS, FORUM -> {
if (channel instanceof TextChannel textChannel) {
return textChannel.sendMessageEmbeds(embedBuilder.build());
yield Optional.of(textChannel.sendMessageEmbeds(embedBuilder.build()));
}
Logger.altitudeLogs.warning("Received channel that is not a text channel " + channel.getType() + " can't send reminder...");
yield Optional.empty();
}
case GUILD_NEWS_THREAD, GUILD_PUBLIC_THREAD, GUILD_PRIVATE_THREAD -> {
if (channel instanceof ThreadChannel threadChannel) {
return threadChannel.sendMessageEmbeds(embedBuilder.build());
yield Optional.of(threadChannel.sendMessageEmbeds(embedBuilder.build()));
}
Logger.altitudeLogs.warning("Received thread that is not a guild thread " + channel.getType() + " can't send reminder...");
yield Optional.empty();
}
default -> Logger.altitudeLogs.warning("Received unexpected channel type " + channel.getType() + " can't send reminder...");
}
return null;
case PRIVATE, VOICE, GROUP, CATEGORY, STAGE, MEDIA, GUILD_DIRECTORY, UNKNOWN -> {
Logger.altitudeLogs.warning("Received unexpected channel type " + channel.getType() + " can't send reminder...");
yield Optional.empty();
}
};
}
private MessageCreateAction getCreateAction(Channel channel, String text) {
@@ -175,9 +190,11 @@ public class ReminderScheduler {
embedBuilder.setAuthor(member.getEffectiveName(), null, member.getEffectiveAvatarUrl());
switch (reminder.reminderType()) {
case NONE, MANUAL -> {
MessageCreateAction createAction = getCreateAction(channel, embedBuilder);
if (createAction == null)
Optional<MessageCreateAction> optionalCreateAction = getCreateAction(channel, embedBuilder);
if (optionalCreateAction.isEmpty())
return;
MessageCreateAction createAction = optionalCreateAction.get();
createAction.queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
case APPEAL -> {
@@ -189,12 +206,12 @@ public class ReminderScheduler {
try {
userId = dataInputStream.readLong();
} catch (IOException e) {
e.printStackTrace();
log.error("Failed to read user id from reminder data", e);
} finally {
try {
dataInputStream.close();
} catch (IOException e) {
e.printStackTrace();
log.error("Failed to close data input stream", e);
}
}
MessageCreateAction messageCreateAction = getCreateAction(channel, "<@" + userId + ">");
@@ -210,9 +227,12 @@ public class ReminderScheduler {
private void sendEmbed(Reminder reminder, Channel channel, EmbedBuilder embedBuilder) {
embedBuilder.setAuthor(reminder.userId() + "");
MessageCreateAction createAction = getCreateAction(channel, embedBuilder);
if (createAction == null)
Optional<MessageCreateAction> optionalMessageCreateAction = getCreateAction(channel, embedBuilder);
if (optionalMessageCreateAction.isEmpty()) {
//Already logged
return;
}
MessageCreateAction createAction = optionalMessageCreateAction.get();
createAction.queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
}
@@ -1,9 +1,8 @@
package com.alttd.selectMenuManager;
import net.dv8tion.jda.api.events.interaction.component.GenericSelectMenuInteractionEvent;
import net.dv8tion.jda.api.components.selections.SelectMenu;
import net.dv8tion.jda.api.components.selections.SelectOption;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
import java.util.List;
@@ -1,7 +1,6 @@
package com.alttd.selectMenuManager;
import com.alttd.selectMenuManager.selectMenus.SelectMenuAuction;
import net.dv8tion.jda.api.events.interaction.component.GenericSelectMenuInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
@@ -20,7 +19,7 @@ public class SelectMenuManager extends ListenerAdapter {
@Override
public void onStringSelectInteraction(@NotNull StringSelectInteractionEvent event) {
String selectMenuId = event.getSelectMenu().getId();
String selectMenuId = event.getSelectMenu().getCustomId();
Optional<DiscordSelectMenu> first = buttons.stream()
.filter(discordModal -> discordModal.getSelectMenuId().equalsIgnoreCase(selectMenuId))
.findFirst();
@@ -8,18 +8,18 @@ import com.alttd.selectMenuManager.DiscordSelectMenu;
import com.alttd.selectMenuManager.SelectMenuManager;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.components.actionrow.ActionRow;
import net.dv8tion.jda.api.components.selections.SelectMenu;
import net.dv8tion.jda.api.components.selections.SelectOption;
import net.dv8tion.jda.api.components.selections.StringSelectMenu;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
import net.dv8tion.jda.api.interactions.components.selections.SelectMenu;
import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
public class SelectMenuAuction extends DiscordSelectMenu {
@@ -55,7 +55,9 @@ public class SelectMenuAuction extends DiscordSelectMenu {
return;
}
List<SelectOption> collect = event.getInteraction().getSelectedOptions().stream().filter(opt -> !opt.isDefault()).collect(Collectors.toList());
List<SelectOption> collect = event.getInteraction().getSelectedOptions().stream()
.filter(opt -> !opt.isDefault())
.toList();
if (collect.isEmpty()) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Received default input"))
.setEphemeral(true).queue();
@@ -67,7 +69,7 @@ public class SelectMenuAuction extends DiscordSelectMenu {
return;
}
SelectOption selectOption = collect.get(0);
SelectOption selectOption = collect.getFirst();
String value = selectOption.getValue();
int bid;
try {
@@ -132,7 +134,8 @@ public class SelectMenuAuction extends DiscordSelectMenu {
}
replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "You successfully made the first bid on this item ($" + Util.formatNumber(currentBid) + ")!"))
.queue();
success.editMessageComponents().setActionRow(auction.getSelectMenu(selectMenuManager, true)).queue();
success.editMessageComponents(ActionRow.of(auction.getSelectMenu(selectMenuManager, true)))
.queue();
},
error -> replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "Unable to finish your bid")).queue())
);
@@ -144,7 +147,7 @@ public class SelectMenuAuction extends DiscordSelectMenu {
.setEphemeral(true).queue();
return null;
}
return embeds.get(0);
return embeds.getFirst();
}
@Override
+1 -1
View File
@@ -13,7 +13,7 @@ public class Logger {
Logger.altitudeLogs = new AltitudeLogs().setTimeFormat("[HH:mm:ss] ");
try {
Logger.altitudeLogs
.setLogPath(new File(AltitudeBot.getInstance().getDataFolder()).getParent() + File.separator + "logs")
.setLogPath(new File(AltitudeBot.getInstance().getDataFolder()) + File.separator + "logs")
.setLogName("debug.log", LogLevel.DEBUG)
.setLogName("info.log", LogLevel.INFO)
.setLogName("warning.log", LogLevel.WARNING)
@@ -0,0 +1,19 @@
package com.alttd.util;
import net.dv8tion.jda.api.entities.Message;
import java.util.HashMap;
public class UserToMessageTracker {
private final HashMap<Long, Message> userToMessageMap = new HashMap<>();
public synchronized void putMessage(long userId, Message message) {
userToMessageMap.put(userId, message);
}
public synchronized Message pullMessage(long userId) {
return userToMessageMap.remove(userId);
}
}
+2
View File
@@ -0,0 +1,2 @@
server:
port: 8001