diff --git a/.gitignore b/.gitignore
index 9268b2e0..a7dcce6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,22 @@
-*.DS_Store
-*.iml
+#################
+## IDEA
+#################
+
+# User-specific stuff
.idea/
+.idea_modules/
.gradle/
+*.iml
+*.DS_Store
+.run/
+
+# IntelliJ
out/
-build/
\ No newline at end of file
+target/
+settings.yaml
+
+techBotSettings.yaml
+
+Archive/
+
+target/
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 00000000..e4b25766
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,2 @@
+
+Copyright (C) 2022 [Greazi](https://greazi.com)
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index c5c85749..00000000
--- a/build.gradle
+++ /dev/null
@@ -1,63 +0,0 @@
-apply plugin: 'java'
-apply plugin: 'com.github.johnrengelman.shadow'
-
-group = "me.TechsCode"
-
-compileJava.options.encoding = 'UTF-8'
-
-assemble.dependsOn shadowJar
-
-repositories {
- mavenLocal()
- mavenCentral()
-
- maven { url 'https://www.jitpack.io' }
- maven { url 'https://m2.dv8tion.net/releases'}
- maven { url 'https://repo.mattmalec.com/repository/releases'}
-}
-
-dependencies {
- implementation ('net.dv8tion:JDA:4.3.0_331') { exclude module: 'opus-java' }
-
- implementation 'com.google.guava:guava:31.1-jre'
- implementation 'org.jsoup:jsoup:1.14.3'
- implementation 'org.apache.commons:commons-lang3:3.12.0'
- implementation 'mysql:mysql-connector-java:8.0.29'
- implementation "com.googlecode.json-simple:json-simple:1.1.1"
- implementation 'net.sourceforge.htmlunit:htmlunit:2.62.0'
- implementation 'com.google.code.gson:gson:2.9.0'
- implementation 'org.kohsuke:github-api:1.306'
- implementation 'com.mattmalec:Pterodactyl4J:2.BETA_78'
-}
-
-buildscript {
- repositories {
- maven {
- url "https://plugins.gradle.org/m2/"
- }
- }
- dependencies {
- classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.4'
- }
-}
-
-shadowJar {
- archiveFileName = 'TechDiscordBot.jar'
- destinationDirectory = file("build")
-}
-
-jar {
- exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
- manifest {
- attributes 'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
- attributes 'Main-Class': 'me.TechsCode.TechDiscordBot.TechDiscordBot'
- }
-}
-
-tasks.withType(JavaCompile) {
- options.encoding = 'UTF-8'
- manifest {
- attributes 'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
- attributes 'Main-Class': 'me.TechsCode.TechDiscordBot.TechDiscordBot'
- }
-}
\ No newline at end of file
diff --git a/build.properties b/build.properties
deleted file mode 100644
index e69de29b..00000000
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index f3d88b1c..00000000
Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 1b16c34a..00000000
--- a/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
deleted file mode 100755
index 2fe81a7d..00000000
--- a/gradlew
+++ /dev/null
@@ -1,183 +0,0 @@
-#!/usr/bin/env sh
-
-#
-# Copyright 2015 the original author or authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-##
-## Gradle start up script for UN*X
-##
-##############################################################################
-
-# 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
-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"'
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
- echo "$*"
-}
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-}
-
-# 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
- ;;
- 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"
- else
- JAVACMD="$JAVA_HOME/bin/java"
- fi
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-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.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-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" ;;
- 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, 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"
-
-exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
deleted file mode 100644
index 9618d8d9..00000000
--- a/gradlew.bat
+++ /dev/null
@@ -1,100 +0,0 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-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.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-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.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
-: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 %CMD_LINE_ARGS%
-
-: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
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 00000000..c189035e
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,105 @@
+
+
+ 4.0.0
+
+ me.techscode
+ techdiscordbot
+
+ TechDiscordBot
+ 0.2.0
+ jar
+
+
+ Greazi
+ me.techscode.techdiscordbot.TechDiscordBot
+
+ 17
+
+ 17
+ 17
+
+ UTF-8
+
+
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
+
+
+ com.greazi
+ DiscordBotFoundation
+ 0.24.0
+
+
+
+
+ com.google.code.gson
+ gson
+ 2.10.1
+
+
+
+ net.sourceforge.tess4j
+ tess4j
+ 5.7.0
+
+
+
+
+
+
+ ${project.name}
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.2
+
+
+
+ ${main.class}
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.10.1
+
+
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
+
+ package
+
+ shade
+
+
+
+
+ false
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
deleted file mode 100644
index 907cb5e1..00000000
--- a/settings.gradle
+++ /dev/null
@@ -1,3 +0,0 @@
-rootProject.name = 'TechDiscordBot'
-
-include ":SpigotAPI"
\ No newline at end of file
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/TechDiscordBot.java b/src/main/java/me/TechsCode/TechDiscordBot/TechDiscordBot.java
index 11fb354c..951beb33 100644
--- a/src/main/java/me/TechsCode/TechDiscordBot/TechDiscordBot.java
+++ b/src/main/java/me/TechsCode/TechDiscordBot/TechDiscordBot.java
@@ -1,288 +1,209 @@
-package me.TechsCode.TechDiscordBot;
-
-import me.TechsCode.TechDiscordBot.module.ModulesManager;
-import me.TechsCode.TechDiscordBot.mysql.MySQLSettings;
-import me.TechsCode.TechDiscordBot.mysql.storage.Storage;
-import me.TechsCode.TechDiscordBot.objects.ChannelQuery;
-import me.TechsCode.TechDiscordBot.objects.Query;
-import me.TechsCode.TechDiscordBot.reminders.ReminderManager;
-import me.TechsCode.TechDiscordBot.songoda.SongodaAPIClient;
-import me.TechsCode.TechDiscordBot.spigotmc.SpigotApi;
-import me.TechsCode.TechDiscordBot.spigotmc.data.APIStatus;
-import me.TechsCode.TechDiscordBot.util.Config;
-import me.TechsCode.TechDiscordBot.util.ConsoleColor;
-import me.TechsCode.TechDiscordBot.util.PterodactylAPI;
-import net.dv8tion.jda.api.JDA;
-import net.dv8tion.jda.api.JDABuilder;
-import net.dv8tion.jda.api.entities.*;
-import net.dv8tion.jda.api.hooks.AnnotatedEventManager;
-import net.dv8tion.jda.api.requests.GatewayIntent;
-import net.dv8tion.jda.api.utils.ChunkingFilter;
-import net.dv8tion.jda.api.utils.MemberCachePolicy;
-import net.dv8tion.jda.api.utils.cache.CacheFlag;
-import okhttp3.OkHttpClient;
-
-import javax.security.auth.login.LoginException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.stream.Collectors;
-
-public class TechDiscordBot {
-
- private static JDA jda;
- private static TechDiscordBot i;
-
- private static Guild guild;
- private static Member self;
-
- private static SpigotApi spigotAPI;
- private static SongodaAPIClient songodaAPIClient;
-// private static List songodaPurchases;
-
- private static Storage storage;
-
- private static String githubToken;
-
- private static ModulesManager modulesManager;
- private static ReminderManager remindersManager;
-
- private static PterodactylAPI pterodactylAPI;
-
- public static void main(String[] args) {
- if (!Config.getInstance().isConfigured()) {
- log(ConsoleColor.RED + "Invalid config file. Please enter the information in config.json");
- return;
- }
-
- try {
- new TechDiscordBot(Config.getInstance().getToken(), Config.getInstance().getApiToken(), Config.getInstance().getSongodaApiToken(), MySQLSettings.of(Config.getInstance().getMySqlHost(), Config.getInstance().getMySqlPort(), Config.getInstance().getMySqlDatabase(), Config.getInstance().getMySqlUsername(), Config.getInstance().getMySqlPassword()), Config.getInstance().getGithubToken(), Config.getInstance().getPteroUrl(), Config.getInstance().getPteroClientToken(), Config.getInstance().getPteroApiToken(), Config.getInstance().getSpigotApiUrl());
- } catch (LoginException | InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- public TechDiscordBot(String token, String apiToken, String songodaApiToken, MySQLSettings mySQLSettings, String githubToken, String pteroUrl, String pteroClientToken, String pteroApiToken, String spigotApiUrl) throws LoginException, InterruptedException {
- i = this;
-
- jda = JDABuilder.createDefault(token)
- .setEnabledIntents(GatewayIntent.getIntents(GatewayIntent.DEFAULT | GatewayIntent.GUILD_MEMBERS.getRawValue() | GatewayIntent.GUILD_BANS.getRawValue()))
- .setDisabledIntents(GatewayIntent.DIRECT_MESSAGE_TYPING, GatewayIntent.GUILD_MESSAGE_TYPING)
- .enableCache(CacheFlag.ONLINE_STATUS)
- .disableCache(CacheFlag.ACTIVITY, CacheFlag.VOICE_STATE)
- .setMemberCachePolicy(MemberCachePolicy.ALL)
- .setChunkingFilter(ChunkingFilter.ALL)
- .setActivity(Activity.watching("for help."))
- .setEventManager(new AnnotatedEventManager())
- .build().awaitReady();
-
- List guilds = jda.getGuilds();
-
- if(guilds.size() > 2) {
- log(ConsoleColor.RED + "The bot is a member of too many guilds. Please leave them all except two!");
- return;
- }
-
- if(guilds.size() == 0) {
- log(ConsoleColor.RED + "The bot is not a member of any guild. Please join a guild!");
- return;
- }
-
- guild = jda.getGuildById("311178000026566658");
- self = guild != null ? guild.getSelfMember() : null;
-
- if(guild == null) {
- log(ConsoleColor.RED + "The bot is not in the right guild!");
- return;
- }
-
- TechDiscordBot.githubToken = githubToken;
-
- spigotAPI = new SpigotApi(spigotApiUrl, apiToken);
- songodaAPIClient = new SongodaAPIClient(songodaApiToken);
-
- log("Initializing MySQL Storage " + mySQLSettings.getHost() + ":" + mySQLSettings.getPort() + "!");
- storage = Storage.of(mySQLSettings);
-
- if(!storage.isConnected()) {
- log(ConsoleColor.RED + "Failed to connect to MySQL!");
- log(storage.getLatestErrorMessage());
- }
-
- pterodactylAPI = new PterodactylAPI();
- pterodactylAPI.setup(pteroUrl, pteroClientToken, pteroApiToken);
-
- modulesManager = new ModulesManager();
- log("Loading modules..");
- modulesManager.load();
-
- remindersManager = new ReminderManager();
- log("Loading reminders..");
- remindersManager.load();
-
- jda.addEventListener(modulesManager);
- jda.addEventListener(remindersManager);
-
- Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.OFF);
-
- log("Successfully loaded the bot and logged into " + guild.getName() + " as " + self.getEffectiveName() + "!");
-
- log("");
-
- log("Spigot:");
- if(!getSpigotStatus().isUsable()) {
- log(" > " + ConsoleColor.RED + "API is not usable!");
- }else{
- log(" > Purchases: " + getSpigotAPI().getSpigotPurchases().size());
- log(" > Resources: " + getSpigotAPI().getSpigotResources().size());
- log(" > Updates: " + getSpigotAPI().getSpigotUpdates().size());
- log(" > Reviews: " + getSpigotAPI().getSpigotReviews().size());
- }
- log("");
-
- log("Market:");
- if(!getMarketStatus().isUsable()) {
- log(" > " + ConsoleColor.RED + "API is not usable!");
- }else{
- log(" > Purchases: " + getSpigotAPI().getMarketPurchases().size());
- log(" > Resources: " + getSpigotAPI().getMarketResources().size());
- log(" > Updates: " + getSpigotAPI().getMarketUpdates().size());
- log(" > Reviews: " + getSpigotAPI().getMarketReviews().size());
- }
- log("");
-
- log("Songoda: ");
- if(getSongodaAPI().isLoaded()) {
- log(" > Purchases: " + getSongodaAPI().getSpigotPurchases().size());
- } else {
- log(" > " + ConsoleColor.RED + "Could not connect. Cannot show info!");
- }
-
- log("");
-
- log("Guild:");
- log(" > Members: " + getGuild().getMembers().size());
- log(" > Verified Members: " + getStorage().retrieveVerifications().stream().filter(v -> guild.getMemberById(v.getDiscordId()) != null).count());
- log(" > Review Squad Members: " + getGuild().getMembers().stream().filter(member -> member.getRoles().stream().anyMatch(role -> role.getName().equals("Review Squad"))).count());
- log(" > Donators: " + getGuild().getMembers().stream().filter(member -> member.getRoles().stream().anyMatch(role -> role.getName().contains("Donator"))).count());
-
- log("");
-
- getModulesManager().logLoad();
-
- log("");
- log("Startup Completed! The bot has successfully started!");
- log("The bot is ready");
- }
-
- public static JDA getJDA() {
- return jda;
- }
-
- public static TechDiscordBot getBot() {
- return i;
- }
-
- public static Guild getGuild() {
- return guild;
- }
-
- public static Member getSelf() {
- return self;
- }
-
- public static Storage getStorage() {
- return storage;
- }
-
- public static SpigotApi getSpigotAPI() {
- return spigotAPI;
- }
-
- public static PterodactylAPI getPterodactylAPI(){return pterodactylAPI;};
-
- public static SongodaAPIClient getSongodaAPI() {
- return songodaAPIClient;
- }
-
- public static ModulesManager getModulesManager() {
- return modulesManager;
- }
-
- public static ReminderManager getRemindersManager() {
- return remindersManager;
- }
-
- public Query getRoles(String... names) {
- List roles = Arrays.stream(names).flatMap(name -> guild.getRolesByName(name, true).stream()).collect(Collectors.toList());
-
- return new Query<>(roles);
- }
-
- public ChannelQuery getChannels(String... names) {
- List channels = Arrays.stream(names).flatMap(name -> guild.getTextChannelsByName(name, true).stream()).collect(Collectors.toList());
- return new ChannelQuery(channels);
- }
-
- public TextChannel getChannel(String id) {
- return guild.getTextChannelById(id);
- }
-
- public Query getCategories(String... names) {
- List channels = Arrays.stream(names).flatMap(name -> guild.getCategoriesByName(name, true).stream()).collect(Collectors.toList());
- return new Query<>(channels);
- }
-
- public Query getMembers(String... names) {
- List channels = Arrays.stream(names).flatMap(name -> guild.getMembersByName(name, true).stream()).collect(Collectors.toList());
- return new Query<>(channels);
- }
-
- public Member getMember(String id) {
- return guild.getMemberById(id);
- }
-
- public Query getEmotes(String... names) {
- List emotes = Arrays.stream(names).flatMap(name -> guild.getEmotesByName(name, true).stream()).collect(Collectors.toList());
-
- return new Query<>(emotes);
- }
-
- public static Member getMemberFromString(Message msg, String s) {
- if (msg.getMentionedMembers().size() > 0) {
- return msg.getMentionedMembers().get(0);
- } else if (getGuild().getMembers().stream().anyMatch(mem -> (mem.getUser().getName() + "#" + mem.getUser().getDiscriminator()).equalsIgnoreCase(s) || mem.getUser().getId().equalsIgnoreCase(s))) {
- return getGuild().getMembers().stream().filter(mem -> (mem.getUser().getName() + "#" + mem.getUser().getDiscriminator()).equalsIgnoreCase(s) || mem.getUser().getId().equalsIgnoreCase(s)).findFirst().orElse(null);
- }
- return null;
- }
-
- public static boolean isStaff(Member member) {
- return member.getRoles().stream().anyMatch(r -> r.getName().contains("Supporter") || r.getName().contains("Staff"));
- }
-
- public static void log(String prefix, String message) {
- System.out.println(prefix + " " + ConsoleColor.RESET + message + ConsoleColor.RESET);
- }
-
- public static void log(String message) {
- System.out.println("[TechPluginSupport] " + message + ConsoleColor.RESET);
- }
-
- public static String getGithubToken() {
- return githubToken;
- }
-
- public static APIStatus getSpigotStatus() {
- return APIStatus.getSpigotStatus(spigotAPI.getSpigotAPIManager());
- }
-
- public static APIStatus getMarketStatus() {
- return APIStatus.getMarketStatus(spigotAPI.getSpigotAPIManager());
- }
-
- public static APIStatus getSongodaStatus() {
- return APIStatus.getStatus(getSongodaAPI());
- }
+package me.techscode.techdiscordbot;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.SimpleBot;
+import com.greazi.discordbotfoundation.utils.color.ConsoleColor;
+import me.techscode.techdiscordbot.actions.buttons.ApplyButton;
+import me.techscode.techdiscordbot.actions.buttons.TicketButtons;
+import me.techscode.techdiscordbot.actions.buttons.verification.*;
+import me.techscode.techdiscordbot.commands.applications.ApplicationCommand;
+import me.techscode.techdiscordbot.commands.common.*;
+import me.techscode.techdiscordbot.commands.console.SayConsoleCommand;
+import me.techscode.techdiscordbot.commands.debug.DatabaseCommand;
+import me.techscode.techdiscordbot.commands.staff.*;
+import me.techscode.techdiscordbot.commands.staff.punishment.BanCommand;
+import me.techscode.techdiscordbot.commands.staff.punishment.KickCommand;
+import me.techscode.techdiscordbot.commands.staff.punishment.TimeoutCommand;
+import me.techscode.techdiscordbot.commands.staff.punishment.WarnCommand;
+import me.techscode.techdiscordbot.commands.tickets.TicketCommand;
+import me.techscode.techdiscordbot.commands.tickets.TicketStaffCommand;
+import me.techscode.techdiscordbot.commands.verification.CodeCommand;
+import me.techscode.techdiscordbot.database.TranscriptSqlManager;
+import me.techscode.techdiscordbot.model.reminders.ReminderManager;
+import me.techscode.techdiscordbot.modules.*;
+
+import java.sql.SQLException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+public final class TechDiscordBot extends SimpleBot {
+
+ public static TranscriptSqlManager transcriptSqlManager;
+
+ private static ReminderManager remindersManager;
+
+ /**
+ * A very ugly way of starting the bot but there is no other way
+ * of doing this. This might get fixed in the feature
+ *
+ * @param args Arguments passed to the bot
+ */
+ public static void main(final String[] args) {
+ // The method that starts the whole bot
+ new SimpleBot() {
+
+ @Override
+ public void onPreLoad() {
+ }
+
+ @Override
+ protected void onBotLoad() {
+ Common.log(Common.consoleLine(),
+ ConsoleColor.CYAN + " Starting the bot " + SimpleBot.getName() + " V" + getVersion(),
+ Common.consoleLine()
+ );
+
+ transcriptSqlManager = new TranscriptSqlManager();
+
+ //Database.MEMBERS.createTable();
+ }
+
+ @Override
+ protected void onBotStart() {
+ }
+
+ @Override
+ protected void onReloadableStart() {
+
+ /*
+ * Register all commands here
+ */
+ registerCommands(
+ new UserInfoCommand(),
+ new CodeCommand(),
+ new GoogleCommand(),
+ new AnswerCommand(),
+ new PluginCommand(),
+ new RemindCommand(),
+ new ApplicationCommand(),
+ new TicketCommand(),
+ new TicketStaffCommand(),
+ new LinkCommand(),
+ new QuestionCommand(),
+ new RoleCommand(),
+ new WikiCommand(),
+ new UpdateCommand()
+ );
+
+ registerCommands(
+ new BanCommand(),
+ new KickCommand(),
+ new TimeoutCommand(),
+ new WarnCommand(),
+ new BotCommands()
+ );
+
+ // Register all debug commands
+ registerCommands(
+ new DatabaseCommand()
+ );
+
+ /*
+ * Add all events here
+ */
+ getJDA().addEventListener(new PrivateMessageReceiveModule());
+ getJDA().addEventListener(new BotMentionModule());
+ getJDA().addEventListener(new MemberJoinModule(), new MemberLeaveModule());
+ getJDA().addEventListener(new RolesModule());
+ getJDA().addEventListener(new MessageReceive());
+
+ /*
+ * Add all console command here
+ */
+ registerConsoleCommand(new SayConsoleCommand());
+
+ /*
+ * All other methods down here
+ */
+ // Send the verification embed
+ /*VerificationModule.embed();
+ TicketModule.embed();
+ ApplyModule.embed();*/
+
+
+ new TicketButtons.TicketButton().build();
+ new ApplyButton.Button().build();
+ new VerifyButton.Button().build();
+
+ remindersManager = new ReminderManager();
+ Common.log("Loading reminders..");
+ try {
+ remindersManager.load();
+ } catch (final SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ jda.addEventListener(remindersManager);
+
+ /*
+ * A new thread to check for preorders
+ * Ugly, but it works
+ */
+ /*if (Settings.Modules.Preorder.enabled) {
+ Common.log("Preorder system enabled",
+ "Checking for preorders every 15 minutes..");
+ // Check the preorders on startup
+ PreorderModule.CheckPreorders();
+
+ new Thread(() -> {
+ while (true) {
+ try {
+ Thread.sleep(TimeUnit.MINUTES.toMillis(15));
+ Debugger.debug("Checking for preorders..");
+ PreorderModule.CheckPreorders();
+ } catch (final InterruptedException e) {
+ Common.throwError(e, "Error while sleeping the preorder thread");
+ }
+ }
+ }).start();
+ }*/
+
+ // Run this method every hour
+ ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+
+ executor.scheduleWithFixedDelay(new Runnable() {
+ @Override
+ public void run() {
+ Common.log("Checking all verification channels..");
+ VerificationModule.pinger(getMainGuild());
+ }
+ }, 5, 60, TimeUnit.MINUTES);
+
+ }
+ };
+ }
+
+ @Override
+ protected void onBotStart() {
+ }
+
+ @Override
+ public String[] getStartupLogo() {
+ return new String[]{
+ " ______ __ ____ _ ______ __ ",
+ " /_ __/__ _____/ /_ / __ \\(_)_____________ _________/ / __ )____ / /_",
+ " / / / _ \\/ ___/ __ \\/ / / / / ___/ ___/ __ \\/ ___/ __ / __ / __ \\/ __/",
+ " / / / __/ /__/ / / / /_/ / (__ ) /__/ /_/ / / / /_/ / /_/ / /_/ / /_ ",
+ "/_/ \\___/\\___/_/ /_/_____/_/____/\\___/\\____/_/ \\__,_/_____/\\____/\\__/ "
+ };
+ }
+
+ @Override
+ public int getFoundedYear() {
+ return 2022;
+ }
+
+ @Override
+ public String getVersion() {
+ return "0.1.25";
+ }
+
+ public static ReminderManager getRemindersManager() {
+ return remindersManager;
+ }
+
+ public static TranscriptSqlManager getTranscriptSqlManager() {
+ return transcriptSqlManager;
+ }
}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/ApplyButton.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/ApplyButton.java
new file mode 100644
index 00000000..006ff6a9
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/ApplyButton.java
@@ -0,0 +1,153 @@
+package me.techscode.techdiscordbot.actions.buttons;
+
+import com.greazi.discordbotfoundation.handlers.buttons.SimpleButton;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.actions.modals.ApplicationModal;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.CompletableFuture;
+
+import static me.techscode.techdiscordbot.modules.ApplyModule.applicationCreate;
+
+public class ApplyButton {
+
+ public static class Button extends SimpleButton {
+
+ public Button() {
+ super("Apply_Create");
+ label("Create Application");
+ emoji(Emoji.fromUnicode("📝"));
+ buttonStyle(ButtonStyle.SUCCESS);
+ disabled(false);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+
+ CompletableFuture future = applicationCreate(getMember(), getGuild());
+ future.thenAccept(channel -> {
+ event.replyEmbeds(new SimpleEmbedBuilder("Application Created")
+ .text(
+ "A new application has been created.",
+ "Please follow the steps in " + channel.getAsMention()
+ )
+ .success().build()).setEphemeral(true).queue();
+ });
+ }
+ }
+
+ public static class GeneralQuestionButton extends SimpleButton {
+
+ public GeneralQuestionButton(@NotNull Member member) {
+ super("AGQ_" + member.getIdLong());
+ label("Answer Questions");
+ emoji(Emoji.fromUnicode("❓"));
+ buttonStyle(ButtonStyle.PRIMARY);
+ disabled(false);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+ event.replyModal(new ApplicationModal.GeneralQuestions(getMember()).build()).queue();
+ this.remove();
+ }
+ }
+
+ public static class SupportQuestions extends SimpleButton {
+
+ public SupportQuestions(@NotNull Member member) {
+ super("AGQS_" + member.getIdLong());
+ label("Answer Questions");
+ emoji(Emoji.fromUnicode("❓"));
+ buttonStyle(ButtonStyle.PRIMARY);
+ disabled(false);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+ event.replyModal(new ApplicationModal.Support(getMember()).build()).queue();
+ this.remove();
+ }
+ }
+
+ public static class DeveloperQuestions extends SimpleButton {
+
+ public DeveloperQuestions(@NotNull Member member) {
+ super("AGQS_" + member.getIdLong());
+ label("Answer Questions");
+ emoji(Emoji.fromUnicode("❓"));
+ buttonStyle(ButtonStyle.PRIMARY);
+ disabled(false);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+ event.replyModal(new ApplicationModal.Developer(getMember()).build()).queue();
+ this.remove();
+ }
+ }
+
+ public static class MarketingQuestions extends SimpleButton {
+
+ public MarketingQuestions(@NotNull Member member) {
+ super("AGQS_" + member.getIdLong());
+ label("Answer Questions");
+ emoji(Emoji.fromUnicode("❓"));
+ buttonStyle(ButtonStyle.PRIMARY);
+ disabled(false);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+ event.replyModal(new ApplicationModal.Marketing(getMember()).build()).queue();
+ this.remove();
+ }
+ }
+
+ public static class CommunityHelperQuestions extends SimpleButton {
+
+ public CommunityHelperQuestions(@NotNull Member member) {
+ super("AGQS_" + member.getIdLong());
+ label("Answer Questions");
+ emoji(Emoji.fromUnicode("❓"));
+ buttonStyle(ButtonStyle.PRIMARY);
+ disabled(false);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+ event.replyModal(new ApplicationModal.CommunityHelper(getMember()).build()).queue();
+ this.remove();
+ }
+ }
+
+ public static class ExitQuestions extends SimpleButton {
+
+ public ExitQuestions(@NotNull Member member) {
+ super("AGQE_" + member.getIdLong());
+ label("Answer Questions");
+ emoji(Emoji.fromUnicode("❓"));
+ buttonStyle(ButtonStyle.PRIMARY);
+ disabled(false);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+ event.replyModal(new ApplicationModal.ExitQuestions(getMember()).build()).queue();
+ this.remove();
+ }
+ }
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/BotActionButtons.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/BotActionButtons.java
new file mode 100644
index 00000000..52d8713d
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/BotActionButtons.java
@@ -0,0 +1,64 @@
+package me.techscode.techdiscordbot.actions.buttons;
+
+import com.greazi.discordbotfoundation.handlers.buttons.SimpleButton;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.actions.modals.ShutdownModal;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import org.jetbrains.annotations.NotNull;
+
+public class BotActionButtons {
+
+ public static class shutdown extends SimpleButton {
+ public shutdown() {
+ super("shutdown");
+ label("CONFIRM SHUTDOWN");
+ buttonStyle(ButtonStyle.DANGER);
+ disabled(false);
+ mainGuildOnly();
+
+ new Thread(() -> {
+ try {
+ Thread.sleep(300000);
+ this.remove();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+
+ event.replyModal(new ShutdownModal(event.getMember().getId()).build()).queue();
+ }
+ }
+
+ public static class restart extends SimpleButton {
+ public restart() {
+ super("restart");
+ label("CONFIRM RESTART");
+ buttonStyle(ButtonStyle.DANGER);
+ disabled(false);
+ mainGuildOnly();
+
+ new Thread(() -> {
+ try {
+ Thread.sleep(300000);
+ this.remove();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Restarting...")
+ .text("The bot is now restarting.")
+ .success().build()).queue();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/DeleteButton.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/DeleteButton.java
new file mode 100644
index 00000000..419891eb
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/DeleteButton.java
@@ -0,0 +1,36 @@
+package me.techscode.techdiscordbot.actions.buttons;
+
+import com.greazi.discordbotfoundation.handlers.buttons.SimpleButton;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+
+import java.util.Objects;
+
+public class DeleteButton extends SimpleButton {
+
+ public DeleteButton(String memberId) {
+ super("x:" + memberId);
+ label("");
+ emoji(Emoji.fromFormatted("❌"));
+ buttonStyle(ButtonStyle.SECONDARY);
+ }
+
+ @Override
+ protected void onButtonInteract(ButtonInteractionEvent event) {
+ String MemberId = event.getButton().getId().split(":")[1];
+
+ Member member = event.getMember();
+
+ if (member.getId().equals(MemberId) || member.getRoles().contains(Objects.requireNonNull(event.getGuild()).getRoleById(Settings.Roles.staff))) {
+ event.getMessage().delete().queue();
+ remove();
+ } else {
+ // Send a message for a quick seconds to show that the button was pressed
+ event.reply("You can't delete this message!").setEphemeral(true).queue(message -> message.deleteOriginal().queue());
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/TicketButtons.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/TicketButtons.java
new file mode 100644
index 00000000..2c385e00
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/TicketButtons.java
@@ -0,0 +1,63 @@
+package me.techscode.techdiscordbot.actions.buttons;
+
+import com.greazi.discordbotfoundation.handlers.buttons.SimpleButton;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.actions.menus.TicketMenus;
+import me.techscode.techdiscordbot.database.entities.SqlTicket;
+import me.techscode.techdiscordbot.modules.TicketModule;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.channel.concrete.Category;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+
+public class TicketButtons {
+
+ public static class TicketButton extends SimpleButton {
+
+ public TicketButton() {
+ super("Ticket_Create");
+ emoji(Emoji.fromUnicode("📨"));
+ label("Create a ticket");
+ buttonStyle(ButtonStyle.SUCCESS);
+ disabled(false);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(final @NotNull ButtonInteractionEvent event) {
+
+ CompletableFuture future = TicketModule.ticketCreate(getMember(), getGuild(), getMember());
+
+ future.thenAccept(channel -> {
+
+ if (channel == null) {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Creation Failed")
+ .text(
+ "Your ticket could not be created.",
+ "You have reached the maximum amount of tickets you can create."
+ )
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+
+ // Send a message to the user
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Created")
+ .text(
+ "Your ticket has been created.",
+ "To complete the ticket creation process, please follow the steps in " + channel.getAsMention()
+ )
+ .success().build()).setEphemeral(true).queue();
+ });
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/verification/VerifyButton.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/verification/VerifyButton.java
new file mode 100644
index 00000000..4fb57fec
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/buttons/verification/VerifyButton.java
@@ -0,0 +1,25 @@
+package me.techscode.techdiscordbot.actions.buttons.verification;
+
+import com.greazi.discordbotfoundation.handlers.buttons.SimpleButton;
+import me.techscode.techdiscordbot.actions.modals.VerificationModal;
+import me.techscode.techdiscordbot.model.enums.Marketplace;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+
+public class VerifyButton {
+
+ public static class Button extends SimpleButton {
+
+ public Button() {
+ super("Verification");
+ label("Verify Purchase");
+ buttonStyle(ButtonStyle.PRIMARY);
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onButtonInteract(ButtonInteractionEvent event) {
+ event.replyModal(new VerificationModal(this.getUser().getId(), Marketplace.SPIGOT).build()).queue();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/ApplyMenu.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/ApplyMenu.java
new file mode 100644
index 00000000..f0bcd421
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/ApplyMenu.java
@@ -0,0 +1,110 @@
+package me.techscode.techdiscordbot.actions.menus;
+
+import com.greazi.discordbotfoundation.handlers.selectmenu.string.SimpleStringSelectMenu;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.actions.buttons.ApplyButton;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.model.enums.Application;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
+import net.dv8tion.jda.api.interactions.components.selections.StringSelectInteraction;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class ApplyMenu extends SimpleStringSelectMenu {
+ public ApplyMenu(@NotNull Member member) {
+ super("APM_" + member.getIdLong());
+ placeholder("Select your position");
+ minMax(1, 1);
+
+ options(
+ SelectOption.of(Application.Position.SUPPORT.getName(), Application.Position.SUPPORT.getId())
+ .withEmoji(Application.Position.SUPPORT.getEmoji())
+ .withDescription(Application.Position.SUPPORT.getDescription()),
+
+ SelectOption.of(Application.Position.DEVELOPER.getName(), Application.Position.DEVELOPER.getId())
+ .withEmoji(Application.Position.DEVELOPER.getEmoji())
+ .withDescription(Application.Position.DEVELOPER.getDescription()),
+
+ SelectOption.of(Application.Position.MARKETING.getName(), Application.Position.MARKETING.getId())
+ .withEmoji(Application.Position.MARKETING.getEmoji())
+ .withDescription(Application.Position.MARKETING.getDescription()),
+
+ SelectOption.of(Application.Position.COMMUNITY_HELPER.getName(), Application.Position.COMMUNITY_HELPER.getId())
+ .withEmoji(Application.Position.COMMUNITY_HELPER.getEmoji())
+ .withDescription(Application.Position.COMMUNITY_HELPER.getDescription())
+ );
+ }
+
+ @Override
+ protected void onMenuInteract(@NotNull StringSelectInteraction event) {
+ final List options = event.getSelectedOptions();
+
+ for (SelectOption option : options) {
+ Application.Position category = Application.Position.getById(option.getValue());
+
+ if (category == null) {
+ event.reply("An error occurred while processing your request.").setEphemeral(true).queue();
+ return;
+ }
+
+ event.getMessage().delete().queue();
+
+ if (category == Application.Position.SUPPORT) {
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Support Application")
+ .text("Please fill out the following form to apply for the Support position.")
+ .field("Did you help people in the past?", "Have you helped people in the past? If so, please explain how you helped them and what you did to help them.", false)
+ .field("What plugin are you most skilled in?", "Please explain what plugin you are most skilled in and why you are most skilled in it.", false)
+ .field("Do you have a microphone?", "Do you have a microphone? If so, are you comfortable to get in a voice chat?", false)
+ .field("Why should we choose you?", "Why should we choose you over other applicants?", false)
+ .field("Other", "Feel free to enter any other information you want to share with us.", false)
+ .build()
+ ).addActionRow(new ApplyButton.SupportQuestions(getMember()).build()).queue();
+ Database.APPLICATIONSTable.setPosition(event.getChannel().getIdLong(), Application.Position.SUPPORT);
+
+ } else if (category == Application.Position.DEVELOPER) {
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Developer Application")
+ .text("Please fill out the following form to apply for the Developer position.")
+ .field("What program languages do you know?", "Please explain what program languages you know and what you are most skilled in.", false)
+ .field("For how long have you been developing?", "How long have you been coding either plugins, websites or other programs?", false)
+ .field("Do you know how to run a project?", "Did you ever run a project in your past? If so, please explain how you ran it and what you did to run it.", false)
+ .field("Do you have a GitHub profile?", "Do you have a GitHub profile? If so, please provide a link to it.", false)
+ .field("Would you sign an NDA?", "Would you sign an NDA (Non-Disclosure Agreement) if we asked you to?", false)
+ .field("Do you have a microphone?", "Do you have a microphone? If so, are you comfortable to get in a voice chat?", false)
+ .field("Why should we choose you?", "Why should we choose you over other applicants?", false)
+ .field("Other", "Feel free to enter any other information you want to share with us.", false)
+ .build()
+ ).addActionRow(new ApplyButton.DeveloperQuestions(getMember()).build()).queue();
+ Database.APPLICATIONSTable.setPosition(event.getChannel().getIdLong(), Application.Position.DEVELOPER);
+
+ } else if (category == Application.Position.MARKETING) {
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Marketing Application")
+ .text("Please fill out the following form to apply for the Marketing position.")
+ .field("What do you expect?", "What do you think you are going to do in our Marketing team?", false)
+ .field("Which section do you prefer?", "What section in the marketing branch do you prefer to work?", false)
+ .field("What is your experience?", "What have you done in the past for activities related to this position?", false)
+ .field("Do you have a graduation?", "Do you have a marketing related graduation? *(not required)*", false)
+ .field("Can you use designer programs?", "Can you use any tools for designing and such. If so, what are these? *(anything from video editing to photo editing)*", false)
+ .field("Do you have a microphone?", "Do you have a microphone? If so, are you comfortable to get in a voice chat?", false)
+ .field("Why should we choose you?", "Why should we choose you over other applicants?", false)
+ .field("Other", "Feel free to enter any other information you want to share with us.", false)
+ .build()
+ ).addActionRow(new ApplyButton.MarketingQuestions(getMember()).build()).queue();
+ Database.APPLICATIONSTable.setPosition(event.getChannel().getIdLong(), Application.Position.MARKETING);
+
+ } else if (category == Application.Position.COMMUNITY_HELPER) {
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Developer Application")
+ .text("Please fill out the following form to apply for the Developer position.")
+ .field("What languages do you speak/write?", "Give a list of languages you speak/write", false)
+ .field("Do you have a GitHub profile?", "Do you have a GitHub profile? If so, please provide a link to it.", false)
+ .field("Do you have a microphone?", "Do you have a microphone? If so, are you comfortable to get in a voice chat?", false)
+ .field("Why should we choose you?", "Why should we choose you over other applicants?", false)
+ .field("Other", "Feel free to enter any other information you want to share with us.", false)
+ .build()
+ ).addActionRow(new ApplyButton.CommunityHelperQuestions(getMember()).build()).queue();
+ Database.APPLICATIONSTable.setPosition(event.getChannel().getIdLong(), Application.Position.COMMUNITY_HELPER);
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/RolesMenu.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/RolesMenu.java
new file mode 100644
index 00000000..51140ebf
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/RolesMenu.java
@@ -0,0 +1,112 @@
+package me.techscode.techdiscordbot.actions.menus;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.handlers.selectmenu.entity.SimpleEntitySelectMenu;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.interactions.components.selections.EntitySelectInteraction;
+import net.dv8tion.jda.api.interactions.components.selections.EntitySelectMenu;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class RolesMenu {
+
+ public static class Add extends SimpleEntitySelectMenu {
+
+ public Add(@NotNull Member member) {
+ super("Add:" + member.getIdLong());
+ placeholder("Select the roles");
+ minMax(1, 10);
+ targetType(EntitySelectMenu.SelectTarget.ROLE);
+ }
+
+ @Override
+ protected void onMenuInteract(EntitySelectInteraction event) {
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ Member targetMember = event.getGuild().getMemberById(target_id);
+ List selectedRoles = event.getMentions().getRoles();
+ StringBuilder roleMentionBuilder = new StringBuilder();
+
+
+ for (Role role : selectedRoles) {
+ assert targetMember != null;
+ if (canUse(event.getMember(), role)) {
+ SimpleRoles.addRole(targetMember, role);
+ roleMentionBuilder.append(role.getAsMention()).append(" ");
+ }
+ }
+
+ event.editMessageEmbeds(new SimpleEmbedBuilder("Added Roles")
+ .text("Successfully added the roles " + roleMentionBuilder.toString() + " to " + targetMember.getAsMention())
+ .success()
+ .build()
+ ).setComponents().queue();
+ }
+ }
+
+ public static class Remove extends SimpleEntitySelectMenu {
+
+ public Remove(@NotNull Member member) {
+ super("Remove:" + member.getIdLong());
+ placeholder("Select the roles");
+ minMax(1, 10);
+ targetType(EntitySelectMenu.SelectTarget.ROLE);
+ }
+
+ @Override
+ protected void onMenuInteract(EntitySelectInteraction event) {
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ Member targetMember = event.getGuild().getMemberById(target_id);
+ List selectedRoles = event.getMentions().getRoles();
+ StringBuilder roleMentionBuilder = new StringBuilder();
+
+
+ for (Role role : selectedRoles) {
+ assert targetMember != null;
+ if (canUse(event.getMember(), role)) {
+ SimpleRoles.removeRole(targetMember, role);
+ roleMentionBuilder.append(role.getAsMention()).append(" ");
+ }
+ }
+
+ event.editMessageEmbeds(new SimpleEmbedBuilder("Remove Roles")
+ .text("Successfully removed the roles " + roleMentionBuilder.toString() + " from " + targetMember.getAsMention())
+ .error()
+ .build()
+ ).setComponents().queue();
+ }
+ }
+
+ private static boolean canUse(Member member, Role role) {
+ List allowedSupporterRoles = new ArrayList();
+ allowedSupporterRoles.add(Settings.Roles.verified);
+ allowedSupporterRoles.add(Settings.Roles.spigot);
+ allowedSupporterRoles.add(Settings.Roles.builtByBit);
+ allowedSupporterRoles.add(Settings.Roles.songoda);
+ allowedSupporterRoles.add(Settings.Roles.polymart);
+ allowedSupporterRoles.add(Settings.Roles.ultraPermissions);
+ allowedSupporterRoles.add(Settings.Roles.ultraPunishments);
+ allowedSupporterRoles.add(Settings.Roles.ultraCustomizer);
+ allowedSupporterRoles.add(Settings.Roles.ultraRegions);
+ allowedSupporterRoles.add(Settings.Roles.ultraEconomy);
+ allowedSupporterRoles.add(Settings.Roles.ultraScoreboards);
+ allowedSupporterRoles.add(Settings.Roles.ultraMotd);
+ allowedSupporterRoles.add(Settings.Roles.insaneShops);
+ allowedSupporterRoles.add(Settings.Roles.insaneVaults);
+
+ if (member.getRoles().contains(SimpleRoles.getRoleById(member.getGuild(), Settings.Roles.supporter))) {
+ return allowedSupporterRoles.contains(role.getIdLong());
+ }
+
+ return member.getPermissions().contains(Permission.ADMINISTRATOR);
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/SelfRolesMenu.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/SelfRolesMenu.java
new file mode 100644
index 00000000..4b1d421c
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/SelfRolesMenu.java
@@ -0,0 +1,155 @@
+package me.techscode.techdiscordbot.actions.menus;
+
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.handlers.selectmenu.string.SimpleStringSelectMenu;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
+import net.dv8tion.jda.api.interactions.components.selections.StringSelectInteraction;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class SelfRolesMenu extends SimpleStringSelectMenu {
+
+ public SelfRolesMenu() {
+ super("selfRolesMenu");
+ placeholder("Select the roles you want to get pings for");
+
+ minMax(0, 6);
+
+ options(
+ SelectOption.of("Plugin Updates", "pluginUpdates")
+ .withEmoji(Emoji.fromFormatted("<:Updates:837724632739217418>"))
+ .withDescription("Get notified when a plugin gets updated"),
+ SelectOption.of("Announcements", "announcements")
+ .withEmoji(Emoji.fromFormatted("<:Announcements:837724632655986718>"))
+ .withDescription("Get notified when a new announcement is made"),
+ SelectOption.of("Patreon News", "patreonNews")
+ .withEmoji(Emoji.fromFormatted("<:PatreonNews:873383006520356964>"))
+ .withDescription("Get notified when a new Patreon news is made"),
+ SelectOption.of("PluginLab", "pluginLab")
+ .withEmoji(Emoji.fromFormatted("<:PluginLab:1045068040615772221>"))
+ .withDescription("Get notified when a new PluginLab is released"),
+ SelectOption.of("Giveaways", "giveaways")
+ .withEmoji(Emoji.fromFormatted("<:giveaways:837724632529895486>"))
+ .withDescription("Get notified when a new giveaway is hosted"),
+ SelectOption.of("Community", "community")
+ .withEmoji(Emoji.fromFormatted("<:TechSupport:681682145823293447>"))
+ .withDescription("Get access to the community channels"),
+ SelectOption.of("Insane Announcer", "insaneAnnouncer")
+ .withEmoji(Emoji.fromFormatted("<:InsaneAnnouncer:741465636231970886>"))
+ .withDescription("Get access to the insane announcer support channel")
+ );
+ }
+
+ @Override
+ protected void onMenuInteract(final StringSelectInteraction event) {
+ final List options = event.getSelectedOptions();
+
+ final boolean updates = false;
+ boolean announcements = false;
+ boolean patreonNews = false;
+ boolean pluginLab = false;
+ boolean giveaways = false;
+ boolean community = false;
+ boolean insaneAnnouncer = false;
+
+
+ final Role updateRole = SimpleRoles.getRoleById(Objects.requireNonNull(event.getGuild()), Settings.Roles.updates);
+
+ final List addedRoles = new ArrayList<>();
+ final List removedRoles = new ArrayList<>();
+
+ for (final SelectOption option : options) {
+ if (option.getValue().equals("pluginUpdates") && SimpleRoles.hasRole(getMember(), updateRole)) {
+ SimpleRoles.removeRole(getMember(), updateRole);
+ removedRoles.add(updateRole);
+ } else if (!SimpleRoles.hasRole(getMember(), updateRole)) {
+ SimpleRoles.addRole(getMember(), updateRole);
+ addedRoles.add(updateRole);
+ }
+ if (option.getValue().equals("announcements")) announcements = true;
+ if (option.getValue().equals("patreonNews")) patreonNews = true;
+ if (option.getValue().equals("pluginLab")) pluginLab = true;
+ if (option.getValue().equals("giveaways")) giveaways = true;
+ if (option.getValue().equals("community")) community = true;
+ if (option.getValue().equals("insaneAnnouncer")) insaneAnnouncer = true;
+ }
+
+ final Role announcementsRole = SimpleRoles.getRoleById(Objects.requireNonNull(event.getGuild()), Settings.Roles.announcements);
+ if (announcements && SimpleRoles.hasRole(getMember(), announcementsRole)) {
+ SimpleRoles.removeRole(getMember(), announcementsRole);
+ removedRoles.add(announcementsRole);
+ } else if (announcements && !SimpleRoles.hasRole(getMember(), announcementsRole)) {
+ SimpleRoles.addRole(getMember(), announcementsRole);
+ addedRoles.add(announcementsRole);
+ }
+
+
+ if (patreonNews) {
+ final Role role = SimpleRoles.getRoleById(Objects.requireNonNull(event.getGuild()), Settings.Roles.patreonNews);
+ if (SimpleRoles.hasRole(getMember(), role)) {
+ SimpleRoles.removeRole(getMember(), role);
+ removedRoles.add(role);
+ } else {
+ SimpleRoles.addRole(getMember(), role);
+ addedRoles.add(role);
+ }
+ }
+
+ if (pluginLab) {
+ final Role role = SimpleRoles.getRoleById(Objects.requireNonNull(event.getGuild()), Settings.Roles.pluginLab);
+ if (SimpleRoles.hasRole(getMember(), role)) {
+ SimpleRoles.removeRole(getMember(), role);
+ removedRoles.add(role);
+ } else {
+ SimpleRoles.addRole(getMember(), role);
+ addedRoles.add(role);
+ }
+ }
+
+ if (giveaways) {
+ final Role role = SimpleRoles.getRoleById(Objects.requireNonNull(event.getGuild()), Settings.Roles.giveaways);
+ if (SimpleRoles.hasRole(getMember(), role)) {
+ SimpleRoles.removeRole(getMember(), role);
+ removedRoles.add(role);
+ } else {
+ SimpleRoles.addRole(getMember(), role);
+ addedRoles.add(role);
+ }
+ }
+
+ if (community) {
+ if (SimpleRoles.hasRole(getMember(), Settings.Roles.community)) {
+ SimpleRoles.removeRole(getMember(), Settings.Roles.community);
+ } else {
+ SimpleRoles.addRole(getMember(), Settings.Roles.community);
+ }
+ }
+
+ if (insaneAnnouncer) {
+ if (SimpleRoles.hasRole(getMember(), Settings.Roles.insaneAnnouncer)) {
+ SimpleRoles.removeRole(getMember(), Settings.Roles.insaneAnnouncer);
+ } else {
+ SimpleRoles.addRole(getMember(), Settings.Roles.insaneAnnouncer);
+ }
+ }
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Roles Updated!")
+ .text(
+ "Your roles have successfully been updated!",
+ "Your roles have either been added or removed upon your selection."
+ )
+ .success().build()
+ ).setEphemeral(true).queue();
+
+
+ // Get the selected roles from the event and check if the user has these roles. If they do do nothing if they haven't add them. And than remove the roles that the user doesn't have selected.
+
+
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/TicketMenus.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/TicketMenus.java
new file mode 100644
index 00000000..690a218a
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/menus/TicketMenus.java
@@ -0,0 +1,718 @@
+package me.techscode.techdiscordbot.actions.menus;
+
+import com.greazi.discordbotfoundation.debug.Debugger;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.handlers.selectmenu.string.SimpleStringSelectMenu;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.model.enums.Plugin;
+import me.techscode.techdiscordbot.model.enums.Ticket;
+import me.techscode.techdiscordbot.modules.TicketModule;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.interactions.components.selections.SelectOption;
+import net.dv8tion.jda.api.interactions.components.selections.StringSelectInteraction;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class TicketMenus {
+
+ public static class TicketMenu extends SimpleStringSelectMenu {
+ public TicketMenu(@NotNull final Member creator) {
+ super("Ticket:" + creator.getId());
+ placeholder("Select your ticket type");
+ minMax(1, 1);
+ options(
+ SelectOption.of(Ticket.Category.PLUGIN.getName(), Ticket.Category.PLUGIN.getId())
+ .withEmoji(Ticket.Category.PLUGIN.getEmoji())
+ .withDescription(Ticket.Category.PLUGIN.getDescription()),
+
+ SelectOption.of(Ticket.Category.PAYMENTS.getName(), Ticket.Category.PAYMENTS.getId())
+ .withEmoji(Ticket.Category.PAYMENTS.getEmoji())
+ .withDescription(Ticket.Category.PAYMENTS.getDescription()),
+
+ SelectOption.of(Ticket.Category.DEVELOPER.getName(), Ticket.Category.DEVELOPER.getId())
+ .withEmoji(Ticket.Category.DEVELOPER.getEmoji())
+ .withDescription(Ticket.Category.DEVELOPER.getDescription()),
+
+ SelectOption.of(Ticket.Category.GIVEAWAY.getName(), Ticket.Category.GIVEAWAY.getId())
+ .withEmoji(Ticket.Category.GIVEAWAY.getEmoji())
+ .withDescription(Ticket.Category.GIVEAWAY.getDescription()),
+
+ SelectOption.of(Ticket.Category.PATREON.getName(), Ticket.Category.PATREON.getId())
+ .withEmoji(Ticket.Category.PATREON.getEmoji())
+ .withDescription(Ticket.Category.PATREON.getDescription()),
+
+ SelectOption.of(Ticket.Category.OTHER.getName(), Ticket.Category.OTHER.getId())
+ .withEmoji(Ticket.Category.OTHER.getEmoji())
+ .withDescription(Ticket.Category.OTHER.getDescription()),
+
+ SelectOption.of("Close", "close")
+ .withEmoji(Emoji.fromUnicode("❌"))
+ .withDescription("Close the ticket")
+ );
+ }
+
+ @Override
+ protected void onMenuInteract(final StringSelectInteraction event) {
+ // Get the ID from the modal ID
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!this.getMember().getId().equals(target_id)) {
+ event.reply("You cannot utilize someone else's menu.").setEphemeral(true).queue();
+ return;
+ }
+
+ final List options = event.getSelectedOptions();
+
+ event.getMessage().delete().queue();
+
+ for (final SelectOption option : options) {
+ switch (option.getValue().toLowerCase()) {
+ case "plugin" -> {
+ StringBuilder plugins = new StringBuilder(
+ "## You haven't bought any plugins yet. You can verify your purchases in <#907349490556616745>\n" +
+ "This means that you **can't** create tickets for premium plugins."
+ );
+ boolean boughtPlugins = false;
+ for (Plugin plugin : Plugin.getOwnedPlugins(getMember())) {
+ if (!boughtPlugins) {
+ plugins.delete(0, plugins.length());
+ boughtPlugins = true;
+ }
+ plugins.append(plugin.getEmojiRaw()).append(" ").append(plugin.getName()).append("\n");
+ }
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Plugin Support")
+ .text(
+ "Please select the plugin you need support for.",
+ "",
+ "**Plugins you own:**",
+ plugins.length() == 0 ? "You haven't verified any premium plugins. You can verify your plugins in <#907349490556616745>\n" : plugins.toString(),
+ "**Free plugins**",
+ Plugin.INSANE_ANNOUNCER.getEmojiRaw() + " " + Plugin.INSANE_ANNOUNCER.getName()
+ )
+ .build()).setActionRow(new PluginMenu(this.getMember()).build()).queue();
+ Debugger.debug("Ticket", "Plugin menu opened");
+ Database.TICKETS.setCategory(event.getChannel().getIdLong(), Ticket.Category.PLUGIN);
+ }
+ case "payments" -> {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Payments")
+ .text(
+ "Please select a sub category.",
+ "",
+ "**Sub categories:**",
+ Ticket.Payment.PAYPAL.getEmojiRaw() + " " + Ticket.Payment.PAYPAL.getName(),
+ Ticket.Payment.MARKETPLACE.getEmojiRaw() + " " + Ticket.Payment.MARKETPLACE.getName(),
+ Ticket.Payment.OTHER.getEmojiRaw() + " " + Ticket.Payment.OTHER.getName()
+ )
+ .build()).setActionRow(new PaymentMenu(this.getMember()).build()).queue();
+ Debugger.debug("Ticket", "Payment menu opened");
+ Database.TICKETS.setCategory(event.getChannel().getIdLong(), Ticket.Category.PAYMENTS);
+ }
+ case "developer" -> {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Developer")
+ .text(
+ "Please select a sub category.",
+ "",
+ "**Sub categories:**",
+ Ticket.Developer.API.getEmojiRaw() + " " + Ticket.Developer.API.getName(),
+ Ticket.Developer.PLUGIN.getEmojiRaw() + " " + Ticket.Developer.PLUGIN.getName(),
+ Ticket.Developer.OTHER.getEmojiRaw() + " " + Ticket.Developer.OTHER.getName()
+ )
+ .build()).setActionRow(new DeveloperMenu(this.getMember()).build()).queue();
+ Debugger.debug("Ticket", "Developer menu opened");
+ Database.TICKETS.setCategory(event.getChannel().getIdLong(), Ticket.Category.DEVELOPER);
+ }
+ case "giveaway" -> {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Giveaways")
+ .text(
+ "Please select a sub category.",
+ "",
+ "**Sub categories:**",
+ Ticket.Giveaway.CLAIM.getEmojiRaw() + " " + Ticket.Giveaway.CLAIM.getName(),
+ Ticket.Giveaway.HOST.getEmojiRaw() + " " + Ticket.Giveaway.HOST.getName()
+ )
+ .build()).setActionRow(new GiveawayMenu(this.getMember()).build()).queue();
+ Debugger.debug("Ticket", "Giveaway menu opened");
+ Database.TICKETS.setCategory(event.getChannel().getIdLong(), Ticket.Category.GIVEAWAY);
+ }
+ case "patreon" -> {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Patreon")
+ .text(
+ "Please select a sub category.",
+ "",
+ "**Sub categories:**",
+ Ticket.Patreon.PERKS.getEmojiRaw() + " " + Ticket.Patreon.PERKS.getName(),
+ Ticket.Patreon.REWARDS.getEmojiRaw() + " " + Ticket.Patreon.REWARDS.getName(),
+ Ticket.Patreon.OTHER.getEmojiRaw() + " " + Ticket.Patreon.OTHER.getName()
+ )
+ .build()).setActionRow(new PatreonMenu(this.getMember()).build()).queue();
+ Debugger.debug("Ticket", "Patreon menu opened");
+ Database.TICKETS.setCategory(event.getChannel().getIdLong(), Ticket.Category.PATREON);
+ }
+ case "other" -> {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Priority")
+ .text(
+ "Now that you have created a ticket you will need to set a priority.",
+ "The priority only shows the staff team how important the ticket is for you.",
+ "",
+ "Note that staff members can change the priority at any time, and without any reason.",
+ "Please select the priority you want to set for your ticket.",
+ "",
+ Ticket.Priority.HIGH.getEmojiRaw() + " **High Priority** - Only be used for critical issues",
+ Ticket.Priority.MEDIUM.getEmojiRaw() + " **Medium Priority** - For non-critical but important issues",
+ Ticket.Priority.LOW.getEmojiRaw() + " **Low Priority** - For non-critical issues",
+ Ticket.Priority.NONE.getEmojiRaw() + " **No Priority** - For matters that are neither essential nor important"
+ )
+ .build()).setActionRow(new PriorityMenu(this.getMember()).build()).queue();
+ Debugger.debug("Ticket", "Priority menu opened");
+ Database.TICKETS.setCategory(event.getChannel().getIdLong(), Ticket.Category.OTHER);
+ }
+ case "close" -> {
+ TicketModule.ticketClose(event.getMember(), Database.TICKETS.get(event.getChannel().getIdLong()).get(0), event.getTimeCreated().toEpochSecond(), "Ticket creation has been canceled", 30000);
+ }
+ default -> {
+ event.replyEmbeds(new SimpleEmbedBuilder("Ticket ERROR")
+ .text(
+ "An error occurred while creating your ticket.",
+ "Please contact staff for further assistance."
+ )
+ .error().build()).setEphemeral(true).queue();
+ Debugger.debug("Ticket", "Unknown option: " + option.getValue());
+ }
+ }
+ }
+ this.remove();
+ }
+ }
+
+ public static class PluginMenu extends SimpleStringSelectMenu {
+
+ public PluginMenu(@NotNull final Member member) {
+ super("TicketPlugin:" + member.getId());
+ placeholder("Select the plugin you need support for");
+ minMax(1, 1);
+
+ final List selectOptionsList = new ArrayList<>();
+ final List memberRoles = member.getRoles();
+
+ if (memberRoles.contains(Plugin.ULTRA_PERMISSIONS.getRole())) {
+ selectOptionsList.add(SelectOption.of("Ultra Permissions", Plugin.ULTRA_PERMISSIONS.getId() + "")
+ .withEmoji(Plugin.ULTRA_PERMISSIONS.getEmoji())
+ .withDescription("Create a ticket for Ultra Permissions")
+ );
+ }
+
+ if (memberRoles.contains(Plugin.ULTRA_CUSTOMIZER.getRole())) {
+ selectOptionsList.add(SelectOption.of("Ultra Customizer", Plugin.ULTRA_CUSTOMIZER.getId() + "")
+ .withEmoji(Plugin.ULTRA_CUSTOMIZER.getEmoji())
+ .withDescription("Create a ticket for Ultra Customizer")
+ );
+ }
+
+ if (memberRoles.contains(Plugin.ULTRA_ECONOMY.getRole())) {
+ selectOptionsList.add(SelectOption.of("Ultra Economy", Plugin.ULTRA_ECONOMY.getId() + "")
+ .withEmoji(Plugin.ULTRA_ECONOMY.getEmoji())
+ .withDescription("Create a ticket for Ultra Economy")
+ );
+ }
+
+ if (memberRoles.contains(Plugin.ULTRA_PUNISHMENTS.getRole())) {
+ selectOptionsList.add(SelectOption.of("Ultra Punishments", Plugin.ULTRA_PUNISHMENTS.getId() + "")
+ .withEmoji(Plugin.ULTRA_PUNISHMENTS.getEmoji())
+ .withDescription("Create a ticket for Ultra Punishments")
+ );
+ }
+
+ if (memberRoles.contains(Plugin.ULTRA_REGIONS.getRole())) {
+ selectOptionsList.add(SelectOption.of("Ultra Regions", Plugin.ULTRA_REGIONS.getId() + "")
+ .withEmoji(Plugin.ULTRA_REGIONS.getEmoji())
+ .withDescription("Create a ticket for Ultra Regions")
+ );
+ }
+
+ if (memberRoles.contains(Plugin.ULTRA_SCOREBOARDS.getRole())) {
+ selectOptionsList.add(SelectOption.of("Ultra Scoreboards", Plugin.ULTRA_SCOREBOARDS.getId() + "")
+ .withEmoji(Plugin.ULTRA_SCOREBOARDS.getEmoji())
+ .withDescription("Create a ticket for Ultra Scoreboards")
+ );
+ }
+
+ if (memberRoles.contains(Plugin.ULTRA_MOTD.getRole())) {
+ selectOptionsList.add(SelectOption.of("Ultra Motd", Plugin.ULTRA_MOTD.getId() + "")
+ .withEmoji(Plugin.ULTRA_MOTD.getEmoji())
+ .withDescription("Create a ticket for Ultra Motd")
+ );
+ }
+
+ if (memberRoles.contains(Plugin.INSANE_SHOPS.getRole())) {
+ selectOptionsList.add(SelectOption.of("Insane Shops", Plugin.INSANE_SHOPS.getId() + "")
+ .withEmoji(Plugin.INSANE_SHOPS.getEmoji())
+ .withDescription("Create a ticket for Insane Shops")
+ );
+ }
+
+ if (memberRoles.contains(Plugin.INSANE_VAULTS.getRole())) {
+ selectOptionsList.add(SelectOption.of("Insane Vaults", Plugin.INSANE_VAULTS.getId() + "")
+ .withEmoji(Plugin.INSANE_VAULTS.getEmoji())
+ .withDescription("Create a ticket for Insane Vaults")
+ );
+ }
+
+ selectOptionsList.add(SelectOption.of("Insane Announcer", Plugin.INSANE_ANNOUNCER.getId() + "")
+ .withEmoji(Plugin.INSANE_ANNOUNCER.getEmoji())
+ .withDescription("Create a ticket for Insane Announcer")
+ );
+ selectOptionsList.add(SelectOption.of("Back", "back")
+ .withEmoji(Emoji.fromUnicode("⏮️"))
+ .withDescription("Go back to the previous menu")
+ );
+
+ options(selectOptionsList);
+ }
+
+ @Override
+ protected void onMenuInteract(final StringSelectInteraction event) {
+ // Get the ID from the modal ID
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!this.getMember().getId().equals(target_id)) {
+ event.reply("You cannot utilize someone else's menu.").setEphemeral(true).queue();
+ return;
+ }
+
+ final List options = event.getSelectedOptions();
+
+ event.getMessage().delete().queue();
+
+ for (final SelectOption option : options) {
+ if (option.getValue().equals("back")) {
+ back(event, getMember());
+ this.remove();
+ return;
+ } else {
+
+ Plugin plugin = Plugin.getPluginById(Integer.parseInt(option.getValue()));
+ assert plugin != null;
+ Database.TICKETS.setType(event.getChannel().getIdLong(), plugin.toString());
+
+ if (SimpleRoles.hasRole(getMember(), Settings.Roles.Patreon.patreon)) {
+
+ // Add the priority to the database
+ Database.TICKETS.setPriority(event.getChannel().getIdLong(), Ticket.Priority.PATREON.toString());
+
+ // Send the ticket creation message
+ TicketModule.finishTicketCreation(event.getChannel().asTextChannel(), getMember());
+
+ return;
+ }
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Ticket creation (3/3)")
+ .text(
+ "Now that you have created a ticket you will need to set a priority.",
+ "The priority only shows the staff team how important the ticket is for you.",
+ "",
+ "Note that staff members can change the priority at any time, and without any reason.",
+ "Please select the priority you want to set for your ticket.",
+ "",
+ Ticket.Priority.HIGH.getEmojiRaw() + " **High Priority** - Only be used for critical issues",
+ Ticket.Priority.MEDIUM.getEmojiRaw() + " **Medium Priority** - For non-critical but important issues",
+ Ticket.Priority.LOW.getEmojiRaw() + " **Low Priority** - For non-critical issues",
+ Ticket.Priority.NONE.getEmojiRaw() + " **No Priority** - For matters that are neither essential nor important"
+ )
+ .build()).setActionRow(new PriorityMenu(this.getMember()).build()).queue();
+ }
+ this.remove();
+ }
+
+ }
+ }
+
+ public static class PaymentMenu extends SimpleStringSelectMenu {
+
+ public PaymentMenu(@NotNull final Member member) {
+ super("TicketPay:" + member.getId());
+ placeholder("Select the payment method you need help with");
+ minMax(1, 1);
+
+ final List selectOptionsList = new ArrayList<>();
+
+ selectOptionsList.add(SelectOption.of("Paypal", Ticket.Payment.PAYPAL.getId().toLowerCase())
+ .withEmoji(Ticket.Payment.PAYPAL.getEmoji())
+ .withDescription(Ticket.Payment.PAYPAL.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Marketplace", Ticket.Payment.MARKETPLACE.getId().toLowerCase())
+ .withEmoji(Ticket.Payment.MARKETPLACE.getEmoji())
+ .withDescription(Ticket.Payment.MARKETPLACE.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Other Payment", Ticket.Payment.OTHER.getId().toLowerCase())
+ .withEmoji(Ticket.Payment.OTHER.getEmoji())
+ .withDescription(Ticket.Payment.OTHER.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Back", "back")
+ .withEmoji(Emoji.fromUnicode("⏮️"))
+ .withDescription("Go back to the previous menu")
+ );
+
+ options(selectOptionsList);
+ }
+
+ @Override
+ protected void onMenuInteract(final StringSelectInteraction event) {
+ // Get the ID from the modal ID
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!this.getMember().getId().equals(target_id)) {
+ event.reply("You cannot utilize someone else's menu.").setEphemeral(true).queue();
+ return;
+ }
+
+ final List options = event.getSelectedOptions();
+
+ event.getMessage().delete().queue();
+
+ for (final SelectOption option : options) {
+ if (option.getValue().equals("back")) {
+ back(event, getMember());
+ this.remove();
+ return;
+ } else {
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Ticket creation (3/3)")
+ .text(
+ "Now that you have created a ticket you will need to set a priority.",
+ "The priority only shows the staff team how important the ticket is for you.",
+ "",
+ "Note that staff members can change the priority at any time, and without any reason.",
+ "Please select the priority you want to set for your ticket.",
+ "",
+ Ticket.Priority.HIGH.getEmojiRaw() + " **High Priority** - Only be used for critical issues",
+ Ticket.Priority.MEDIUM.getEmojiRaw() + " **Medium Priority** - For non-critical but important issues",
+ Ticket.Priority.LOW.getEmojiRaw() + " **Low Priority** - For non-critical issues",
+ Ticket.Priority.NONE.getEmojiRaw() + " **No Priority** - For matters that are neither essential nor important"
+ )
+ .build()).setActionRow(new PriorityMenu(this.getMember()).build()).queue();
+
+ Database.TICKETS.setType(event.getChannel().getIdLong(), Ticket.Payment.valueOf(option.getValue().toUpperCase()).getId());
+ }
+ this.remove();
+ }
+
+ }
+ }
+
+ public static class DeveloperMenu extends SimpleStringSelectMenu {
+
+ public DeveloperMenu(@NotNull final Member member) {
+ super("TicketDev:" + member.getId());
+ placeholder("Select what kind of help you need");
+ minMax(1, 1);
+
+ final List selectOptionsList = new ArrayList<>();
+
+ selectOptionsList.add(SelectOption.of("API", Ticket.Developer.API.getId())
+ .withEmoji(Ticket.Developer.API.getEmoji())
+ .withDescription(Ticket.Developer.API.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Plugin", Ticket.Developer.PLUGIN.getId())
+ .withEmoji(Ticket.Developer.PLUGIN.getEmoji())
+ .withDescription(Ticket.Developer.PLUGIN.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Other", Ticket.Developer.OTHER.getId())
+ .withEmoji(Ticket.Developer.OTHER.getEmoji())
+ .withDescription(Ticket.Developer.OTHER.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Back", "back")
+ .withEmoji(Emoji.fromUnicode("⏮️"))
+ .withDescription("Go back to the previous menu")
+ );
+
+ options(selectOptionsList);
+ }
+
+ @Override
+ protected void onMenuInteract(final StringSelectInteraction event) {
+ // Get the ID from the modal ID
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!this.getMember().getId().equals(target_id)) {
+ event.reply("You cannot utilize someone else's menu.").setEphemeral(true).queue();
+ return;
+ }
+
+ final List options = event.getSelectedOptions();
+
+ event.getMessage().delete().queue();
+
+ for (final SelectOption option : options) {
+ if (option.getValue().equals("back")) {
+ back(event, getMember());
+ this.remove();
+ return;
+ } else {
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Ticket creation (3/3)")
+ .text(
+ "Now that you have created a ticket you will need to set a priority.",
+ "The priority only shows the staff team how important the ticket is for you.",
+ "",
+ "Note that staff members can change the priority at any time, and without any reason.",
+ "Please select the priority you want to set for your ticket.",
+ "",
+ Ticket.Priority.HIGH.getEmojiRaw() + " **High Priority** - Only be used for critical issues",
+ Ticket.Priority.MEDIUM.getEmojiRaw() + " **Medium Priority** - For non-critical but important issues",
+ Ticket.Priority.LOW.getEmojiRaw() + " **Low Priority** - For non-critical issues",
+ Ticket.Priority.NONE.getEmojiRaw() + " **No Priority** - For matters that are neither essential nor important"
+ )
+ .build()).setActionRow(new PriorityMenu(this.getMember()).build()).queue();
+
+ Database.TICKETS.setType(event.getChannel().getIdLong(), Ticket.Developer.valueOf(option.getValue().toUpperCase()).getId());
+ }
+ this.remove();
+ }
+
+ }
+ }
+
+ public static class GiveawayMenu extends SimpleStringSelectMenu {
+
+ public GiveawayMenu(@NotNull final Member member) {
+ super("TicketGiveaway:" + member.getId());
+ placeholder("Claim or host a giveaway");
+ minMax(1, 1);
+
+ final List selectOptionsList = new ArrayList<>();
+
+ selectOptionsList.add(SelectOption.of("Claim", Ticket.Giveaway.CLAIM.getId())
+ .withEmoji(Ticket.Giveaway.CLAIM.getEmoji())
+ .withDescription(Ticket.Giveaway.CLAIM.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Host", Ticket.Giveaway.HOST.getId())
+ .withEmoji(Ticket.Giveaway.HOST.getEmoji())
+ .withDescription(Ticket.Giveaway.HOST.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Back", "back")
+ .withEmoji(Emoji.fromUnicode("⏮️"))
+ .withDescription("Go back to the previous menu")
+ );
+
+ options(selectOptionsList);
+ }
+
+ @Override
+ protected void onMenuInteract(final StringSelectInteraction event) {
+ // Get the ID from the modal ID
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!this.getMember().getId().equals(target_id)) {
+ event.reply("You cannot utilize someone else's menu.").setEphemeral(true).queue();
+ return;
+ }
+
+ final List options = event.getSelectedOptions();
+
+ event.getMessage().delete().queue();
+
+ for (final SelectOption option : options) {
+ if (option.getValue().equals("back")) {
+ back(event, getMember());
+ this.remove();
+ return;
+ } else {
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Ticket creation (3/3)")
+ .text(
+ "Now that you have created a ticket you will need to set a priority.",
+ "The priority only shows the staff team how important the ticket is for you.",
+ "",
+ "Note that staff members can change the priority at any time, and without any reason.",
+ "Please select the priority you want to set for your ticket.",
+ "",
+ Ticket.Priority.HIGH.getEmojiRaw() + " **High Priority** - Only be used for critical issues",
+ Ticket.Priority.MEDIUM.getEmojiRaw() + " **Medium Priority** - For non-critical but important issues",
+ Ticket.Priority.LOW.getEmojiRaw() + " **Low Priority** - For non-critical issues",
+ Ticket.Priority.NONE.getEmojiRaw() + " **No Priority** - For matters that are neither essential nor important"
+ )
+ .build()).setActionRow(new PriorityMenu(this.getMember()).build()).queue();
+
+ Database.TICKETS.setType(event.getChannel().getIdLong(), Ticket.Giveaway.valueOf(option.getValue().toUpperCase()).getId());
+ }
+ this.remove();
+ }
+
+ }
+ }
+
+ public static class PatreonMenu extends SimpleStringSelectMenu {
+
+ public PatreonMenu(@NotNull final Member member) {
+ super("TicketPatreon:" + member.getId());
+ placeholder("Help for our Patreon program");
+ minMax(1, 1);
+
+ final List selectOptionsList = new ArrayList<>();
+
+ selectOptionsList.add(SelectOption.of("Perks", Ticket.Patreon.PERKS.getId())
+ .withEmoji(Ticket.Patreon.PERKS.getEmoji())
+ .withDescription(Ticket.Patreon.PERKS.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Rewards", Ticket.Patreon.REWARDS.getId())
+ .withEmoji(Ticket.Patreon.REWARDS.getEmoji())
+ .withDescription(Ticket.Patreon.REWARDS.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Other", Ticket.Patreon.OTHER.getId())
+ .withEmoji(Ticket.Patreon.OTHER.getEmoji())
+ .withDescription(Ticket.Patreon.OTHER.getDescription())
+ );
+ selectOptionsList.add(SelectOption.of("Back", "back")
+ .withEmoji(Emoji.fromUnicode("⏮️"))
+ .withDescription("Go back to the previous menu")
+ );
+
+ options(selectOptionsList);
+ }
+
+ @Override
+ protected void onMenuInteract(final StringSelectInteraction event) {
+ // Get the ID from the modal ID
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!this.getMember().getId().equals(target_id)) {
+ event.reply("You cannot utilize someone else's menu.").setEphemeral(true).queue();
+ return;
+ }
+
+ final List options = event.getSelectedOptions();
+
+ event.getMessage().delete().queue();
+
+ for (final SelectOption option : options) {
+ if (option.getValue().equals("back")) {
+ back(event, getMember());
+ this.remove();
+ return;
+ } else {
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Ticket creation (3/3)")
+ .text(
+ "Now that you have created a ticket you will need to set a priority.",
+ "The priority only shows the staff team how important the ticket is for you.",
+ "",
+ "Note that staff members can change the priority at any time, and without any reason.",
+ "Please select the priority you want to set for your ticket.",
+ "",
+ Ticket.Priority.HIGH.getEmojiRaw() + " **High Priority** - Only be used for critical issues",
+ Ticket.Priority.MEDIUM.getEmojiRaw() + " **Medium Priority** - For non-critical but important issues",
+ Ticket.Priority.LOW.getEmojiRaw() + " **Low Priority** - For non-critical issues",
+ Ticket.Priority.NONE.getEmojiRaw() + " **No Priority** - For matters that are neither essential nor important"
+ )
+ .build()).setActionRow(new PriorityMenu(this.getMember()).build()).queue();
+
+ Database.TICKETS.setType(event.getChannel().getIdLong(), Ticket.Patreon.valueOf(option.getValue().toUpperCase()).getId());
+ }
+ this.remove();
+ }
+
+ }
+ }
+
+ public static class PriorityMenu extends SimpleStringSelectMenu {
+ public PriorityMenu(@NotNull final Member member) {
+ super("TicketPriority:" + member.getId());
+ placeholder("Select a priority");
+ minMax(1, 1);
+ options(
+ SelectOption.of("High Priority", "high")
+ .withEmoji(Emoji.fromFormatted("<:high_priority:694648884332331008>"))
+ .withDescription("Only be used for critical issues"),
+ SelectOption.of("Medium Priority", "medium")
+ .withEmoji(Emoji.fromFormatted("<:medium_priority:694648883980009593>"))
+ .withDescription("For non-critical but important issues"),
+ SelectOption.of("Low Priority", "low")
+ .withEmoji(Emoji.fromFormatted("<:low_priority:694648884353433601>"))
+ .withDescription("For non-critical issues"),
+ SelectOption.of("No Priority", "none")
+ .withEmoji(Emoji.fromFormatted("<:offline:496493395187990538>"))
+ .withDescription("For matters that are neither essential nor important")
+ );
+ }
+
+ @Override
+ protected void onMenuInteract(final StringSelectInteraction event) {
+ // Get the ID from the modal ID
+ final String target_id = Objects.requireNonNull(event.getSelectMenu().getId()).split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!this.getMember().getId().equals(target_id)) {
+ event.reply("You cannot utilize someone else's menu.").setEphemeral(true).queue();
+ return;
+ }
+
+ // Get the options that have been selected
+ final List options = event.getSelectedOptions();
+
+ // Delete the old message
+ event.getMessage().delete().queue();
+
+ // Set the priority to default none
+ Ticket.Priority priority = Ticket.Priority.NONE;
+
+ // Get the priority
+ for (final SelectOption option : options) {
+ switch (option.getValue()) {
+ case "high":
+ priority = Ticket.Priority.HIGH;
+ break;
+ case "medium":
+ priority = Ticket.Priority.MEDIUM;
+ break;
+ case "low":
+ priority = Ticket.Priority.LOW;
+ break;
+ case "no":
+ priority = Ticket.Priority.NONE;
+ break;
+ }
+ }
+
+ // Add the priority to the database
+ Database.TICKETS.setPriority(event.getChannel().getIdLong(), priority.toString());
+
+ // Send the ticket creation message
+ TicketModule.finishTicketCreation(event.getChannel().asTextChannel(), getMember());
+
+ this.remove();
+ }
+ }
+
+ private static void back(StringSelectInteraction event, Member member) {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket")
+ .text(
+ "Please select what kind of ticket you want to create.",
+ "",
+ "**Available categories:**",
+ Ticket.Category.PLUGIN.getEmojiRaw() + " " + Ticket.Category.PLUGIN.getName() + " - " + Ticket.Category.PLUGIN.getDescription(),
+ Ticket.Category.PAYMENTS.getEmojiRaw() + " " + Ticket.Category.PAYMENTS.getName() + " - " + Ticket.Category.PAYMENTS.getDescription(),
+ Ticket.Category.DEVELOPER.getEmojiRaw() + " " + Ticket.Category.DEVELOPER.getName() + " - " + Ticket.Category.DEVELOPER.getDescription(),
+ Ticket.Category.GIVEAWAY.getEmojiRaw() + " " + Ticket.Category.GIVEAWAY.getName() + " - " + Ticket.Category.GIVEAWAY.getDescription(),
+ Ticket.Category.PATREON.getEmojiRaw() + " " + Ticket.Category.PATREON.getName() + " - " + Ticket.Category.PATREON.getDescription(),
+ Ticket.Category.OTHER.getEmojiRaw() + " " + Ticket.Category.OTHER.getName() + " - " + Ticket.Category.OTHER.getDescription(),
+ "",
+ "*Please keep in mind that in order to access support for any premium resource, you must first verify your purchase.*"
+ )
+ .build()
+ ).setActionRow(new TicketMenu(member).build()).queue();
+
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/ApplicationModal.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/ApplicationModal.java
new file mode 100644
index 00000000..cab8952c
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/ApplicationModal.java
@@ -0,0 +1,371 @@
+package me.techscode.techdiscordbot.actions.modals;
+
+import com.greazi.discordbotfoundation.handlers.modals.SimpleModal;
+import com.greazi.discordbotfoundation.handlers.modals.SimpleTextInput;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.actions.buttons.ApplyButton;
+import me.techscode.techdiscordbot.actions.menus.ApplyMenu;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.model.enums.Application;
+import me.techscode.techdiscordbot.modules.ApplyModule;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
+import org.jetbrains.annotations.NotNull;
+
+public class ApplicationModal {
+
+ public static class GeneralQuestions extends SimpleModal {
+
+ public GeneralQuestions(@NotNull Member member) {
+ super("AGQ-" + member.getIdLong());
+ mainGuildOnly();
+ title("General Application Questions");
+
+ final SimpleTextInput nameQuestion = new SimpleTextInput("nameage", "What is your name and age?");
+ nameQuestion.setRequired();
+ nameQuestion.setParagraph();
+
+ final SimpleTextInput timezoneQuestion = new SimpleTextInput("timezone", "What is your timezone?");
+ timezoneQuestion.setRequired();
+ timezoneQuestion.setParagraph();
+
+ final SimpleTextInput availableTimeQuestion = new SimpleTextInput("time", "Available time per week?");
+ availableTimeQuestion.setRequired();
+ availableTimeQuestion.setParagraph();
+
+ final SimpleTextInput whyQuestion = new SimpleTextInput("why", "Why do you want to join?");
+ whyQuestion.setRequired();
+ whyQuestion.setParagraph();
+
+ final SimpleTextInput proConQuestion = new SimpleTextInput("procon", "Pro's and Con's");
+ proConQuestion.setRequired();
+ proConQuestion.setParagraph();
+
+ textInputs(nameQuestion, timezoneQuestion, availableTimeQuestion, whyQuestion, proConQuestion);
+ }
+
+ @Override
+ protected void onModalInteract(@NotNull ModalInteractionEvent event) {
+
+ event.getMessage().delete().queue();
+
+ final String nameage = event.getValue("nameage").getAsString();
+ final String timezone = event.getValue("timezone").getAsString();
+ final String time = event.getValue("time").getAsString();
+ final String why = event.getValue("why").getAsString();
+ final String procon = event.getValue("procon").getAsString();
+
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("General Application Questions")
+ .field("What is your name and age?", nameage, false)
+ .field("What is your timezone?", timezone, false)
+ .field("Available time per week?", time, false)
+ .field("Why do you want to join?", why, false)
+ .field("Pro's and Con's", procon, false)
+ .build()).queue();
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Which position?")
+ .text("Now that we know a bit more about you, which position would you like to apply for?")
+ .field("Support", "Help people with their problems", false)
+ .field("Developer", "Help our developer team", false)
+ .field("Marketing", "Help our marketing team, maintain our socials and more", false)
+ .field("Translator", "Help our team by translating our plugins", false)
+ .build()
+ ).addActionRow(new ApplyMenu(getMember()).build()).queue();
+
+ }
+ }
+
+ public static class Support extends SimpleModal {
+
+ public Support(@NotNull Member member) {
+ super("ASQ-" + member.getIdLong());
+ mainGuildOnly();
+ title("Support Application Questions");
+
+ final SimpleTextInput pastQuestion = new SimpleTextInput("past", "Did you help people in the past?");
+ pastQuestion.setRequired();
+ pastQuestion.setParagraph();
+
+ final SimpleTextInput skillQuestion = new SimpleTextInput("skill", "What plugin are you most skilled in?");
+ skillQuestion.setRequired();
+ skillQuestion.setParagraph();
+
+ final SimpleTextInput micQuestion = new SimpleTextInput("microphone", "Do you have a microphone?");
+ micQuestion.setRequired();
+ micQuestion.setParagraph();
+
+ final SimpleTextInput whyQuestion = new SimpleTextInput("why", "Why should we choose you?");
+ whyQuestion.setRequired();
+ whyQuestion.setParagraph();
+
+ final SimpleTextInput otherQuestion = new SimpleTextInput("other", "Other");
+ otherQuestion.setRequired();
+ otherQuestion.setParagraph();
+
+ textInputs(pastQuestion, skillQuestion, micQuestion, whyQuestion, otherQuestion);
+
+ this.remove();
+ }
+
+ @Override
+ protected void onModalInteract(@NotNull ModalInteractionEvent event) {
+
+ event.getMessage().delete().queue();
+ event.reply("Success!").setEphemeral(true).queue(message -> message.deleteOriginal().queue());
+
+ final String past = event.getValue("past").getAsString();
+ final String skill = event.getValue("skill").getAsString();
+ final String mic = event.getValue("microphone").getAsString();
+ final String why = event.getValue("why").getAsString();
+ final String other = event.getValue("other").getAsString();
+
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Support Application Questions")
+ .field("Did you help people in the past?", past, false)
+ .field("What plugin are you most skilled in?", skill, false)
+ .field("Do you have a microphone?", mic, false)
+ .field("Why should we choose you?", why, false)
+ .field("Other", other, false)
+ .build()).queue();
+
+ ApplyModule.finishApplicationCreation(event.getChannel().asTextChannel(), getMember());
+
+ this.remove();
+ }
+ }
+
+ public static class Developer extends SimpleModal {
+
+ public Developer(@NotNull Member member) {
+ super("ADQ-" + member.getIdLong());
+ mainGuildOnly();
+ title("Developer Application Questions");
+
+ final SimpleTextInput langQuestion = new SimpleTextInput("lang", "What program languages do you know?");
+ langQuestion.setRequired();
+ langQuestion.setParagraph();
+
+ final SimpleTextInput timeQuestion = new SimpleTextInput("time", "For how long have you been developing?");
+ timeQuestion.setRequired();
+ timeQuestion.setParagraph();
+
+ final SimpleTextInput projectQuestion = new SimpleTextInput("projectrun", "Do you know how to run a project?");
+ projectQuestion.setRequired();
+ projectQuestion.setParagraph();
+
+ final SimpleTextInput gitQuestion = new SimpleTextInput("git", "Do you have a GitHub profile?");
+ gitQuestion.setRequired();
+ gitQuestion.setParagraph();
+
+ final SimpleTextInput ndaQuestion = new SimpleTextInput("nda", "Would you sign an NDA?");
+ ndaQuestion.setRequired();
+ ndaQuestion.setParagraph();
+
+ textInputs(langQuestion, timeQuestion, projectQuestion, gitQuestion, ndaQuestion);
+ }
+
+ @Override
+ protected void onModalInteract(@NotNull ModalInteractionEvent event) {
+
+ event.getMessage().delete().queue();
+ event.reply("Success!").setEphemeral(true).queue(message -> message.deleteOriginal().queue());
+
+ final String lang = event.getValue("lang").getAsString();
+ final String time = event.getValue("time").getAsString();
+ final String project = event.getValue("projectrun").getAsString();
+ final String git = event.getValue("git").getAsString();
+ final String nda = event.getValue("nda").getAsString();
+
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Developer Application Questions")
+ .field("What program languages do you know?", lang, false)
+ .field("For how long have you been developing?", time, false)
+ .field("Do you know how to run a project?", project, false)
+ .field("Do you have a GitHub profile?", git, false)
+ .field("Would you sign an NDA?", nda, false)
+ .build()).queue();
+
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Final Questions")
+ .text("These are the final questions for your application. Please answer them as good as possible.")
+ .field("Do you have a microphone?", "Do you have a microphone? If so, are you comfortable to get in a voice chat?", false)
+ .field("Why should we choose you?", "Why should we choose you over other applicants?", false)
+ .field("Other", "Feel free to enter any other information you want to share with us.", false)
+ .build()
+ ).addActionRow(new ApplyButton.ExitQuestions(getMember()).build()).queue();
+
+ this.remove();
+ }
+ }
+
+ public static class Marketing extends SimpleModal {
+
+ public Marketing(@NotNull Member member) {
+ super("AMQ-" + member.getIdLong());
+ mainGuildOnly();
+ title("Marketing Application Questions");
+
+ final SimpleTextInput expectation = new SimpleTextInput("expectation", "What do you expect?");
+ expectation.setRequired();
+ expectation.setParagraph();
+
+ final SimpleTextInput section = new SimpleTextInput("section", "Which section do you prefer?");
+ section.setRequired();
+ section.setParagraph();
+
+ final SimpleTextInput experience = new SimpleTextInput("experience", "What is your experience?");
+ experience.setRequired();
+ experience.setParagraph();
+
+ final SimpleTextInput graduation = new SimpleTextInput("graduation", "Do you have a graduation?");
+ graduation.setRequired();
+ graduation.setParagraph();
+
+ final SimpleTextInput design = new SimpleTextInput("design", "Can you use designer programs?");
+ design.setRequired();
+ design.setParagraph();
+
+ textInputs(expectation, section, experience, graduation, design);
+ }
+
+ @Override
+ protected void onModalInteract(@NotNull ModalInteractionEvent event) {
+
+ event.getMessage().delete().queue();
+ event.reply("Success!").setEphemeral(true).queue(message -> message.deleteOriginal().queue());
+
+ final String expectation = event.getValue("expectation").getAsString();
+ final String section = event.getValue("section").getAsString();
+ final String experience = event.getValue("experience").getAsString();
+ final String graduation = event.getValue("graduation").getAsString();
+ final String design = event.getValue("design").getAsString();
+
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Marketing Application Questions")
+ .field("What do you expect?", expectation, false)
+ .field("Which section do you prefer?", section, false)
+ .field("What is your experience?", experience, false)
+ .field("Do you have a graduation?", graduation, false)
+ .field("Can you use designer programs?", design, false)
+ .build()).queue();
+
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Final Questions")
+ .text("These are the final questions for your application. Please answer them as good as possible.")
+ .field("Do you have a microphone?", "Do you have a microphone? If so, are you comfortable to get in a voice chat?", false)
+ .field("Why should we choose you?", "Why should we choose you over other applicants?", false)
+ .field("Other", "Feel free to enter any other information you want to share with us.", false)
+ .build()
+ ).addActionRow(new ApplyButton.ExitQuestions(getMember()).build()).queue();
+
+ this.remove();
+ }
+ }
+
+ public static class CommunityHelper extends SimpleModal {
+
+ public CommunityHelper(@NotNull Member member) {
+ super("ACHQ-" + member.getIdLong());
+ mainGuildOnly();
+ title("Community Helper Application Questions");
+
+ final SimpleTextInput language = new SimpleTextInput("lang", "What languages do you speak/write?");
+ language.setRequired();
+ language.setParagraph();
+
+ final SimpleTextInput git = new SimpleTextInput("git", "Do you have a GitHub profile?");
+ git.setRequired();
+ git.setParagraph();
+
+ final SimpleTextInput microphone = new SimpleTextInput("microphone", "Do you have a microphone?");
+ microphone.setRequired();
+ microphone.setParagraph();
+
+ final SimpleTextInput why = new SimpleTextInput("why", "Why should we choose you?");
+ why.setRequired();
+ why.setParagraph();
+
+ final SimpleTextInput other = new SimpleTextInput("other", "Other");
+ other.setRequired();
+ other.setParagraph();
+
+ textInputs(language, git, microphone, why, other);
+ }
+
+ @Override
+ protected void onModalInteract(@NotNull ModalInteractionEvent event) {
+
+ event.getMessage().delete().queue();
+ event.reply("Success!").setEphemeral(true).queue(message -> message.deleteOriginal().queue());
+
+ final String language = event.getValue("lang").getAsString();
+ final String git = event.getValue("git").getAsString();
+ final String microphone = event.getValue("microphone").getAsString();
+ final String why = event.getValue("why").getAsString();
+ final String other = event.getValue("other").getAsString();
+
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Community Helper Application Questions")
+ .field("What languages do you speak/write?", language, false)
+ .field("Do you have a GitHub profile?", git, false)
+ .field("Do you have a microphone?", microphone, false)
+ .field("Why should we choose you?", why, false)
+ .field("Other", other, false)
+ .build()).queue();
+
+ ApplyModule.finishApplicationCreation(event.getChannel().asTextChannel(), getMember());
+
+ this.remove();
+ }
+ }
+
+ public static class ExitQuestions extends SimpleModal {
+
+ public ExitQuestions(@NotNull Member member) {
+ super("AEQ-" + member.getIdLong());
+ mainGuildOnly();
+ title("Final Application Questions");
+
+ final SimpleTextInput microphone = new SimpleTextInput("microphone", "Do you have a microphone?");
+ microphone.setRequired();
+ microphone.setParagraph();
+
+ final SimpleTextInput why = new SimpleTextInput("why", "Why should we choose you?");
+ why.setRequired();
+ why.setParagraph();
+
+ final SimpleTextInput other = new SimpleTextInput("other", "Other");
+ other.setRequired();
+ other.setParagraph();
+
+ textInputs(microphone, why, other);
+ }
+
+ @Override
+ protected void onModalInteract(@NotNull ModalInteractionEvent event) {
+
+ event.getMessage().delete().queue();
+ event.reply("Success!").setEphemeral(true).queue(message -> message.deleteOriginal().queue());
+
+ final String microphone = event.getValue("microphone").getAsString();
+ final String why = event.getValue("why").getAsString();
+ final String other = event.getValue("other").getAsString();
+
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Community Helper Application Questions")
+ .field("Do you have a microphone?", microphone, false)
+ .field("Why should we choose you?", why, false)
+ .field("Other", other, false)
+ .build()).queue();
+
+ if (Database.APPLICATIONSTable.get(event.getChannel().getIdLong()).get(0).getCategory() == Application.Position.MARKETING) {
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Making an announcement")
+ .text("Now that you have filled in the application, we would like to see how you would make an announcement with the following information.",
+ "",
+ "We are going to release a new plugin in the up coming week called Ultra Economy. There has been asked to make an announcement about this plugin.",
+ "",
+ "The plugin will be released next week and will be available on SpigotMC. The plugin will be €10,-- and will be available for preorder first for a week. After that, the plugin will be released for everyone."
+ )
+ .build()
+ ).queue();
+ }
+
+ ApplyModule.finishApplicationCreation(event.getChannel().asTextChannel(), getMember());
+
+ this.remove();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/ShutdownModal.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/ShutdownModal.java
new file mode 100644
index 00000000..fbcc2216
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/ShutdownModal.java
@@ -0,0 +1,61 @@
+package me.techscode.techdiscordbot.actions.modals;
+
+import com.greazi.discordbotfoundation.handlers.modals.SimpleModal;
+import com.greazi.discordbotfoundation.handlers.modals.SimpleTextInput;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Objects;
+
+public class ShutdownModal extends SimpleModal {
+
+ public ShutdownModal(final String discord_id) {
+ super("Shutdown:" + discord_id);
+ mainGuildOnly();
+ title("Confirm Shutdown");
+
+ final SimpleTextInput confirmQuestion = new SimpleTextInput("confirm", "Type in \"Confirm\" to confirm the shutdown.");
+ confirmQuestion.setRequired();
+ confirmQuestion.setMinMaxLength(7, 7);
+
+ textInputs(confirmQuestion);
+ }
+
+ /**
+ * The execution once the modal has been submitted
+ *
+ * @param event ModalInteractionEvent
+ */
+ @Override
+ protected void onModalInteract(@NotNull final ModalInteractionEvent event) {
+ // Get the user and member from the event
+ final User user = event.getUser();
+
+ // Get the target ID of the event before doing anything else
+ final String target_id = event.getModalId().split(":")[1];
+
+ // Check if the member is the person who requested the ticket
+ if (!user.getId().equals(target_id)) {
+ event.reply("You can't fill in a modal that is meant for someone else").setEphemeral(true).queue();
+ return;
+ }
+
+ if (!Objects.requireNonNull(event.getValue("confirm")).getAsString().equals("CONFIRM")) {
+ event.reply("You didn't type in \"Confirm\"!").setEphemeral(true).queue();
+ return;
+ }
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Shutdown")
+ .text(
+ "Shutting down...",
+ "Thank you for using Tech's Code Discord Bot!"
+ )
+ .build()).setEphemeral(true).queue();
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/TicketModal.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/TicketModal.java
new file mode 100644
index 00000000..07ecf6df
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/TicketModal.java
@@ -0,0 +1,64 @@
+package me.techscode.techdiscordbot.actions.modals;
+
+import com.greazi.discordbotfoundation.handlers.modals.SimpleModal;
+import com.greazi.discordbotfoundation.handlers.modals.SimpleTextInput;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.MessageEmbed;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
+import org.jetbrains.annotations.NotNull;
+
+public class TicketModal extends SimpleModal {
+
+ /**
+ * Set the modal details
+ */
+ public TicketModal(final String discord_id, final String plugin) {
+ super("Ticket:" + discord_id + ":" + plugin);
+ mainGuildOnly();
+ title("Ticket | " + plugin);
+
+ final SimpleTextInput supportQuestion = new SimpleTextInput("question", "Your support question");
+ supportQuestion.setRequired();
+ supportQuestion.setParagraph();
+
+ textInputs(supportQuestion);
+ }
+
+ /**
+ * The execution once the modal has been submitted
+ *
+ * @param event ModalInteractionEvent
+ */
+ @Override
+ protected void onModalInteract(@NotNull final ModalInteractionEvent event) {
+ // Get the user and member from the event
+ final User user = event.getUser();
+ final Member member = event.getMember();
+
+ // Get the target ID of the event before doing anything else
+ final String target_id = event.getModalId().split(":")[1];
+
+ // Check if the member is the person who requested the ticket
+ if (!user.getId().equals(target_id)) {
+ event.reply("You can't fill in a modal that is meant for someone else").setEphemeral(true).queue();
+ return;
+ }
+
+ // Create the loading embed
+ final MessageEmbed embed = new SimpleEmbedBuilder("Ticket")
+ .text("Creating a new ticket for you...")
+ .thumbnail("https://i.imgur.com/9TETTf5.gif")
+ .build();
+
+ // Message method, so we can edit the message later on
+ event.replyEmbeds(embed).setEphemeral(true).queue(message -> {
+
+ // Get the rest of the information plugin and support question
+ final int plugin = Integer.parseInt(event.getModalId().split(":")[2]);
+ final String supportQuestion = event.getValue("question").getAsString();
+
+ });
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/VerificationModal.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/VerificationModal.java
new file mode 100644
index 00000000..a1010d8a
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/VerificationModal.java
@@ -0,0 +1,192 @@
+package me.techscode.techdiscordbot.actions.modals;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.handlers.modals.SimpleModal;
+import com.greazi.discordbotfoundation.handlers.modals.SimpleTextInput;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.database.entities.SqlTicket;
+import me.techscode.techdiscordbot.model.enums.Marketplace;
+import me.techscode.techdiscordbot.model.enums.Ticket;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.channel.concrete.Category;
+import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+/**
+ * The Verification Modal
+ */
+public class VerificationModal extends SimpleModal {
+
+ /**
+ * Set the modal details
+ */
+ public VerificationModal(final String discord_id, final Marketplace marketplace) {
+ super("Verification:" + discord_id + ":" + marketplace.getId());
+ mainGuildOnly();
+ title("Verification | " + marketplace.getName());
+
+ final SimpleTextInput emailInput = new SimpleTextInput("email", "Paypal Email address");
+ emailInput.setRequired();
+
+ final SimpleTextInput transactionInput = new SimpleTextInput("transaction", "Transaction ID (Only 1)");
+ transactionInput.setRequired();
+ transactionInput.setMinMaxLength(17, 19);
+
+ final SimpleTextInput marketplaceInput = new SimpleTextInput("link", "Marketplace profile link");
+ marketplaceInput.setRequired();
+ marketplaceInput.setMinMaxLength(35, 100);
+
+ textInputs(emailInput, transactionInput, marketplaceInput);
+
+ // Remove the button with this.remove() after 10 minutes of creation of the button
+ new Thread(() -> {
+ try {
+ Thread.sleep(600000);
+ this.remove();
+ } catch (InterruptedException e) {
+ Common.throwError(e, "Error while removing button");
+ }
+ }).start();
+ }
+
+ /**
+ * The execution once the modal has been submitted
+ *
+ * @param event ModalInteractionEvent
+ */
+ @Override
+ protected void onModalInteract(@NotNull final ModalInteractionEvent event) {
+
+ // Get the ID from the modal ID
+ final String target_id = event.getModalId().split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!this.getMember().getId().equals(target_id)) {
+ event.reply("Something is going honorably wrong! Please try to verify your purchase again.").setEphemeral(true).queue();
+ return;
+ }
+
+ // Get the input values
+ final String email = event.getValue("email").getAsString();
+ final String transaction = event.getValue("transaction").getAsString();
+ final String link = event.getValue("link").getAsString();
+
+ Guild guild = event.getGuild();
+ Member owner = event.getMember();
+
+ // Permissions list for the ticket channel
+ final List permissions = new ArrayList<>(
+ Arrays.asList(
+ Permission.VIEW_CHANNEL,
+ Permission.MESSAGE_HISTORY,
+ Permission.MESSAGE_SEND,
+ Permission.MESSAGE_ATTACH_FILES,
+ Permission.MESSAGE_EMBED_LINKS,
+ Permission.MESSAGE_ADD_REACTION,
+ Permission.MANAGE_EMOJIS_AND_STICKERS
+ )
+ );
+
+ // Get the members name if the members name can't be gathered it will use the user's ID
+ final String memberName;
+ if (Objects.equals(owner.getNickname(), "") || owner.getNickname() == null) {
+ if (owner.getEffectiveName().equals("")) {
+ memberName = owner.getUser().getId();
+ } else {
+ owner.getEffectiveName();
+ memberName = owner.getEffectiveName();
+ }
+ } else {
+ memberName = owner.getNickname();
+ }
+
+ // Get some settings from the settings file
+ final Category category = guild.getCategoryById("1168185109543931964");
+ final long staffRole = Settings.Roles.support;
+
+ // Create the application channel for the member
+ guild.createTextChannel("verification-" + memberName, category)
+ .addPermissionOverride(guild.getPublicRole(), null, permissions)
+ // Add staff permissions
+ .addRolePermissionOverride(staffRole, permissions, null)
+ // Add member permissions
+ .addMemberPermissionOverride(owner.getIdLong(), permissions, Collections.singleton(Permission.MESSAGE_SEND))
+ .queue(channel -> {
+
+ channel.sendMessageEmbeds(new SimpleEmbedBuilder("📨 Ticket")
+ .text(
+ "Thank you for your verification request!",
+ "",
+ "Please wait for a staff member to respond to your ticket.",
+ "",
+ "**Please note that this process can take up to 24 hours.**",
+ "",
+ "Email: `" + email + "`",
+ "Transaction ID: `" + transaction + "`",
+ "Marketplace: `" + link + "`"
+ )
+ .build()
+ ).queue();
+
+ new SqlTicket(this.getUser().getIdLong(), channel.getIdLong(), channel.getTimeCreated().toEpochSecond(), Ticket.Category.PAYMENTS.getId(), Ticket.Payment.VERIFICATION.getId(), Ticket.Priority.HIGH.getId()).save();
+
+ event.replyEmbeds(new SimpleEmbedBuilder("Verification Created")
+ .text("Your verification ticket has been created! Please wait for a staff member to respond to your ticket.",
+ "",
+ "Your verification request: " + channel.getAsMention()
+ )
+ .build()).setEphemeral(true).queue();
+
+ channel.sendMessage("<@&" + Settings.Roles.support + ">").queue();
+ });
+
+ /*
+ // Set up the loading embed.
+ final MessageEmbed embed = new SimpleEmbedBuilder("Verification")
+ .text("Verifying your details...")
+ .thumbnail("https://i.imgur.com/jcuD6gb.gif")
+ .build();
+
+ // get the values from the modal ID
+ final Marketplace marketplace = Marketplace.getFromId(Integer.parseInt(event.getModalId().split(":")[2]));
+
+ /*event.replyEmbeds(new SimpleEmbedBuilder("Verification")
+ .text(
+ "Thank you for filling in the form.",
+ "",
+ "We will verify your purchase as soon as possible.",
+ "",
+ "*Please note that this process can take up to 24 hours.*",
+ "*Also note that if the transaction ID does not match the email address, the verification will be denied.*"
+ ).success().build()).setEphemeral(true).queue();
+
+ event.getGuild().getTextChannelById(Settings.Modules.Verification.manualVerification).sendMessageEmbeds(
+ new SimpleEmbedBuilder("Verification")
+ .text("A manual verification request has been made by " + getMember().getAsMention() + "!")
+ .field("User", getMember().getAsMention() + " (" + getMember().getId() + ")", true)
+ .field("Marketplace", Marketplace.getNamed(marketplace), true)
+ .field("Profile link", link, true)
+ .field("Transaction ID", transaction, true)
+ .field("E-mail", email, false)
+ .build()
+ ).queue();*/
+
+ /*final List linkComponents = List.of(link.split("/"));
+ final int marketplaceId = Integer.parseInt(linkComponents.get(linkComponents.size() - 1).split("\\.")[1]);
+
+ Debugger.debug("Verification", "Marketplace ID: " + marketplaceId);
+
+ // !!! DISABLED !!! due to the fact that the API is not yet ready
+ // Send the loading embed and verify the purchase
+ event.replyEmbeds(embed).setEphemeral(true).queue(message -> {
+ if (Paypal.verify(this.getMember(), message, email, marketplaceId, transaction, marketplace)) {
+ Paypal.getPurchases(message, this.getMember(), email, marketplace, marketplaceId);
+ }
+ });*/
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/VerificationPreModal.java b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/VerificationPreModal.java
new file mode 100644
index 00000000..70054dd5
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/actions/modals/VerificationPreModal.java
@@ -0,0 +1,107 @@
+package me.techscode.techdiscordbot.actions.modals;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.handlers.modals.SimpleModal;
+import com.greazi.discordbotfoundation.handlers.modals.SimpleTextInput;
+import com.greazi.discordbotfoundation.utils.RandomGenerator;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.model.enums.Marketplace;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.MessageEmbed;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
+import org.jetbrains.annotations.NotNull;
+
+public class VerificationPreModal extends SimpleModal {
+
+ /**
+ * Set the modal details
+ */
+ public VerificationPreModal(final String discord_id, final Marketplace marketplace) {
+ super("VPR:" + discord_id + ":" + marketplace.getId());
+ mainGuildOnly();
+ title("Verification | " + marketplace.getName());
+
+ final SimpleTextInput link = new SimpleTextInput("link", "Marketplace profile link");
+ link.setRequired();
+
+ final SimpleTextInput images = new SimpleTextInput("images", "Bought plugins list (images)");
+ images.setRequired();
+ images.setParagraph();
+ images.setPlaceholder("Add your images to a system like Imgur and paste the links here");
+
+ textInputs(link, images);
+
+ // Remove the button with this.remove() after 10 minutes of creation of the button
+ new Thread(() -> {
+ try {
+ Thread.sleep(600000);
+ this.remove();
+ } catch (InterruptedException e) {
+ Common.throwError(e, "Error while removing button");
+ }
+ }).start();
+ }
+
+ /**
+ * The execution once the modal has been submitted
+ *
+ * @param event ModalInteractionEvent
+ */
+ @Override
+ protected void onModalInteract(@NotNull final ModalInteractionEvent event) {
+ // Get static methods
+ final User user = event.getUser();
+ final Member member = event.getMember();
+
+ // Get the ID from the modal ID
+ final String target_id = event.getModalId().split(":")[1];
+
+ // Check if the member is the person who wants to verify
+ if (!user.getId().equals(target_id)) {
+ event.reply("Something is going honorably wrong! Please try to verify your purchase again.").setEphemeral(true).queue();
+ return;
+ }
+
+ final String code = RandomGenerator.string(16);
+
+ // Set up the loading embed.
+ final MessageEmbed embed = new SimpleEmbedBuilder("Verification")
+ .text(
+ "Hi there " + member.getAsMention() + ",",
+ "",
+ "Before we can verify your purchase, we need to make sure you are the owner of that account.",
+ "Please make a post on your marketplace profile with the following message:",
+ "`TechVerification." + code + "`",
+ "",
+ "Thank you for filling in the form! We will review your purchase and get back to you as soon as possible",
+ "When your purchase has been reviewed, you will receive a DM from the bot or a mention in <#" + Settings.Modules.Verification.pingChannel + ">"
+ ).build();
+
+ // get the values from the modal ID
+ String marketplace_id = event.getModalId().split(":")[2];
+ final Marketplace marketplace = Marketplace.getFromId(marketplace_id);
+
+ // Get the input values
+ final String link = event.getValue("link").getAsString();
+ final String images = event.getValue("images").getAsString();
+
+
+ // Send the loading embed and verify the purchase
+ event.replyEmbeds(embed).setEphemeral(true).queue();
+
+ // Send the verification request in the manual verification channel
+ assert marketplace != null;
+ event.getGuild().getTextChannelById(Settings.Modules.Verification.manualVerification).sendMessageEmbeds(
+ new SimpleEmbedBuilder("Verification")
+ .text("A manual verification request has been made by " + member.getAsMention() + "!")
+ .field("User", member.getNickname() + " (" + member.getEffectiveName() + " " + member.getId() + ")", true)
+ .field("Marketplace", marketplace.getName(), true)
+ .field("Profile Link", link, true)
+ .field("Verification Code", code, true)
+ .field("Images", images, false)
+ .build()
+ ).queue();
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/client/APIClient.java b/src/main/java/me/TechsCode/TechDiscordBot/client/APIClient.java
deleted file mode 100644
index 8715e95f..00000000
--- a/src/main/java/me/TechsCode/TechDiscordBot/client/APIClient.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package me.TechsCode.TechDiscordBot.client;
-
-public class APIClient extends Thread {
- private final String token;
-
- public APIClient(String token) {
- this.token = token;
-
- start();
- }
-
- public String getToken() {
- return token;
- }
-}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/applications/ApplicationCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/applications/ApplicationCommand.java
new file mode 100644
index 00000000..692486a4
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/applications/ApplicationCommand.java
@@ -0,0 +1,79 @@
+package me.techscode.techdiscordbot.commands.applications;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.entities.SqlApplication;
+import me.techscode.techdiscordbot.modules.ApplyModule;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import static me.techscode.techdiscordbot.modules.ApplyModule.applicationCreate;
+
+public class ApplicationCommand extends SimpleSlashCommand {
+
+ public ApplicationCommand() {
+ super("application");
+
+ mainGuildOnly();
+
+ subCommands(
+ new SubcommandData("create", "Create a ticket"),
+ new SubcommandData("close", "Close a ticket")
+ );
+ }
+
+ @Override
+ protected void onCommand(@NotNull SlashCommandInteractionEvent event) {
+
+ String subCommand = event.getSubcommandName();
+
+ assert subCommand != null;
+ if(subCommand.equals("create")) {
+ // Create the ticket channel
+ CompletableFuture future = applicationCreate(getMember(), getGuild());
+ future.thenAccept(channel -> {
+ // Send a message to the user
+ event.replyEmbeds(new SimpleEmbedBuilder("Application Created")
+ .text(
+ "A new application has been created.",
+ "Please follow the steps in " + channel.getAsMention()
+ )
+ .success().build()).setEphemeral(true).queue();
+ });
+
+ } else if(subCommand.equals("close")) {
+ long channelId = event.getChannel().getIdLong();
+ List sqlApplications = Database.APPLICATIONSTable.get(channelId);
+
+ if (sqlApplications.size() == 0) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Ticket Not Found")
+ .text("This channel is not a application. Please use this command in a application channel.",
+ "If you think this is a mistake, please contact a staff member.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+
+ for (SqlApplication sqlApplication : sqlApplications) {
+ if (sqlApplication.getChannelId() != channelId) continue;
+ if (sqlApplication.getMember().get(0).getDiscordId() == event.getMember().getIdLong() || SimpleRoles.hasRole(event.getMember(), Settings.Roles.staff)) {
+ // Close the ticket
+ ApplyModule.applicationClose(sqlApplication.getChannel(), event.getTimeCreated().toEpochSecond());
+ event.reply("Application closed").setEphemeral(true).queue(message -> message.deleteOriginal().queue());
+ } else {
+ event.replyEmbeds(new SimpleEmbedBuilder("Not a owner or Staff member")
+ .text("You are not the owner of this Application or a staff member. There for you can't close it.")
+ .error().build()).setEphemeral(true).queue();
+ }
+ return;
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/common/AnswerCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/AnswerCommand.java
new file mode 100644
index 00000000..226459c1
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/AnswerCommand.java
@@ -0,0 +1,73 @@
+package me.techscode.techdiscordbot.commands.common;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+
+import java.util.Objects;
+
+/**
+ * TODO: Fix all the commands and finish this file!
+ */
+public class AnswerCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public AnswerCommand() {
+ super("answer");
+ description("give pre made answers to question");
+
+ mainGuildOnly();
+
+ subCommands(
+ new SubcommandData("hex", "Hex & gradient explanation"),
+ new SubcommandData("placeholderapi", "PlaceholderAPI explanation"),
+ new SubcommandData("test", "Test something out but no idea what!")
+
+ );
+ }
+
+ /**
+ * The main code of the timeout command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+
+ switch (Objects.requireNonNull(event.getSubcommandName())) {
+ case "hex":
+ event.replyEmbeds(
+ new SimpleEmbedBuilder("How To Use Hex & Gradient")
+ .text("In order to use **Hex** and **Gradients** in Ultra and Insane plugins," +
+ "you will have to use two different formats.\n" +
+ "\n" +
+ "__For Hex Colors__ >\n" +
+ "```\n" +
+ "{#RRGGBB}Some Text```\n" +
+ "__For Gradients Colors__ >\n" +
+ "```{#RRGGBB>}Some Text{#RRGGBB<}```\n" +
+ "To be able to create gradient colors in an easier way and having a preview of them you can use this [**website**](https://rgb.techscode.com/), you have to select as `Type` **TechsCode {#rrggbb>}** then write the text you want to use in `Message`, after modify the colors and finally copy the text where it will be written `Output`.")
+ .success().build()
+ ).queue();
+ break;
+ case "placeholderapi":
+ event.replyEmbeds(
+ new SimpleEmbedBuilder("How To Use Placeholders")
+ .text("In order to use **Placedholers** in Ultra and Insane plugins," +
+ "you will need to install [PlaceholderAPI](https://www.spigotmc.org/resources/placeholderapi.6245/).\n" +
+ "\n" +
+ "A list of all possible placeholders can be found [**HERE**](https://github.com/PlaceholderAPI/PlaceholderAPI/wiki/Placeholders)\n" +
+ "For a list of all our plugin placeholders, you will need to check our plugin wiki pages for each plugin you want to use placeholders from.")
+ .success().build()
+ ).queue();
+ case "test":
+ event.reply(com.eaio.util.text.HumanTime.approximately("29 m 30m 100 ms")).queue();
+ break;
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/common/GoogleCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/GoogleCommand.java
new file mode 100644
index 00000000..faecdee3
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/GoogleCommand.java
@@ -0,0 +1,88 @@
+package me.techscode.techdiscordbot.commands.common;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionMapping;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import org.jetbrains.annotations.NotNull;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+public class GoogleCommand extends SimpleSlashCommand {
+
+ public GoogleCommand() {
+ // Set the command
+ super("google");
+ // Set the description of the command
+ description("Google something on the web");
+ // Set the options for the command
+ options(new OptionData(OptionType.STRING, "search", "Your search phrase", true),
+ new OptionData(OptionType.USER, "member", "The member for who the search is", false));
+ // Set to only the main guild
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onCommand(@NotNull final SlashCommandInteractionEvent event) {
+
+ String search = Objects.requireNonNull(event.getOption("search")).getAsString();
+ String queryUrl = null;
+
+ try {
+ search = search.trim();
+ search = URLEncoder
+ .encode(search, StandardCharsets.UTF_8);
+ queryUrl = "https://www.google.com/search?q=" + search;
+
+ } catch (final Exception exception) {
+ Common.throwError(exception, "Something went wrong while searching for " + search);
+ }
+
+ if (queryUrl == null) {
+ event.replyEmbeds(new SimpleEmbedBuilder("ERROR")
+ .text("Something went wrong while searching for " + search)
+ .error()
+ .build()
+ ).setEphemeral(true).queue();
+ }
+
+ OptionMapping targetOption = event.getOption("member");
+
+ if (targetOption == null) {
+ event.replyEmbeds(
+ new SimpleEmbedBuilder("Google")
+ .text(
+ "Hi there,",
+ "It seems that you don't know how to use google.",
+ "No problem at all, here is an example on how to google.",
+ "",
+ "Here is a google search for your question: " + queryUrl,
+ "",
+ "We hope this helps!"
+ )
+ .build()
+ ).setEphemeral(true).queue();
+ } else {
+ event.reply("Success!").setEphemeral(true).queue(message -> {message.deleteOriginal().queue();});
+ event.getChannel().sendMessage(targetOption.getAsUser().getAsMention()).addEmbeds(
+ new SimpleEmbedBuilder("Google")
+ .text(
+ "Hi there,",
+ "It seems that you don't know how to use google.",
+ "No problem at all, here is an example on how to google.",
+ "",
+ "Here is a google search for your question: " + queryUrl,
+ "",
+ "We hope this helps!"
+ )
+ .build()
+ ).queue();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/common/LinkCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/LinkCommand.java
new file mode 100644
index 00000000..45bf1603
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/LinkCommand.java
@@ -0,0 +1,90 @@
+package me.techscode.techdiscordbot.commands.common;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.model.enums.Plugin;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+
+import java.awt.*;
+import java.util.Objects;
+
+public class LinkCommand extends SimpleSlashCommand {
+
+ public LinkCommand() {
+ super("link");
+ description("Will return a link to one of our websites");
+
+ subCommands(new SubcommandData("addon", "Returns the addon website"),
+ new SubcommandData("guides", "Returns the UC Guide website"),
+ new SubcommandData("insaneeditor", "Return the InsaneEditor website"),
+ new SubcommandData("polymart", "Returns the Polymart website"),
+ new SubcommandData("songoda", "Returns the Songoda website"),
+ new SubcommandData("spigot", "Returns the Spigot website"),
+ new SubcommandData("translations", "Returns the translations website")
+ );
+ }
+
+ @Override
+ protected void onCommand(SlashCommandInteractionEvent event) {
+ String subcommandData = event.getSubcommandName();
+
+ switch (Objects.requireNonNull(subcommandData)) {
+ case "addon" -> event.replyEmbeds(new SimpleEmbedBuilder("Addon Website")
+ .text("All our addon's are stored and manged thru our addons website.",
+ "https://ultraadditions.com/",
+ "",
+ "Welcome to the page where you can find, download, and upload addons to TechsCode's Plugins. Enhancing the capabilities of UltraCustomizer and UltraRegions.")
+ .color(new Color(192, 38, 211))
+ .build()).queue();
+ case "guides" -> event.replyEmbeds(new SimpleEmbedBuilder("Guides Website")
+ .text("Guides give more and a detailed example of how to setup or create a system for Ultra Customizer.",
+ "https://guides.techscode.com",
+ "",
+ "The guides website provides a simple website on how to use Ultra Customizer en on how to create a system. (This page might be integrated in to the main website in the future)")
+ .color(new Color(174, 84, 206))
+ .image("https://i.imgur.com/KBw2szW.png")
+ .build()).queue();
+ case "insaneeditor" -> event.replyEmbeds(new SimpleEmbedBuilder("Insane Editor")
+ .text("Use a web interface to edit in game settings and values of some of our plugins",
+ "**Under maintenance**",
+ "",
+ "This website allows you to edit permissions and settings for our plugins. Currently it is offline and being updated to a newer and faster system.")
+ .color(new Color(113, 225, 207))
+ .image("https://i.imgur.com/4C08sQD.jpg")
+ .build()).queue();
+ case "polymart" -> event.replyEmbeds(new SimpleEmbedBuilder("Polymart")
+ .text("Polymart is a marketplace where we sell our resources",
+ "https://polymart.org/user/techscode.5485",
+ "",
+ "Buy our resources from our marketplace and verify your purchase here: <#907349490556616745>")
+ .color(new Color(3, 160, 146))
+ .image("https://i.imgur.com/1PXzrRg.png")
+ .build()).queue();
+ case "songoda" -> event.replyEmbeds(new SimpleEmbedBuilder("Songoda")
+ .text("Songoda is a marketplace where we sell our resources",
+ "https://songoda.com/profile/techscode",
+ "",
+ "Buy our resources from our marketplace and verify your purchase here: <#907349490556616745>")
+ .color(new Color(252, 73, 74))
+ .image("https://i.imgur.com/oKeIpv4.png")
+ .build()).queue();
+ case "spigot" -> event.replyEmbeds(new SimpleEmbedBuilder("SpigotMC")
+ .text("SpigotMC is a marketplace where we sell our resources",
+ "https://www.spigotmc.org/members/techscode.29620/",
+ "",
+ "Buy our resources from our marketplace and verify your purchase here: <#907349490556616745>")
+ .color(new Color(238, 135, 19))
+ .image("https://i.imgur.com/wlbnhwI.png")
+ .build()).queue();
+ case "translations" -> event.replyEmbeds(new SimpleEmbedBuilder("Translations repository")
+ .text("All our translations can be found on our translation repository.",
+ "https://github.com/TechsCode-Team/PluginTranslations",
+ "",
+ "GitHub - TechsCode-Team/PluginTranslations: A repository holding the translations for our plugins.")
+ .color(new Color(67, 178, 255))
+ .image("https://imgur.com/M2bHbUx.png")
+ .build()).queue();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/common/PluginCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/PluginCommand.java
new file mode 100644
index 00000000..ea48acb5
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/PluginCommand.java
@@ -0,0 +1,59 @@
+package me.techscode.techdiscordbot.commands.common;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+import java.util.Objects;
+
+/**
+ * TODO: Fix all the commands and finish this file!
+ */
+public class PluginCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public PluginCommand() {
+ super("plugin");
+ description("Get info/links about a plugin");
+
+ mainGuildOnly();
+
+ options(new OptionData(OptionType.STRING, "plugin", "Select a plugin", true)
+ .addChoice("Vault", "Vault")
+ .addChoice("PlaceholderAPI", "PlaceholderAPI")
+ .addChoice("ProtocolLib", "ProtocolLib")
+ .addChoice("TAB", "TAB")
+ .addChoice("NametagEdit", "NametagEdit"));
+ }
+
+ // TODO: Make better embeds
+
+ /**
+ * The main code of the timeout command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ final String topic = Objects.requireNonNull(event.getOption("plugin")).getAsString();
+
+ if (topic.equalsIgnoreCase("Vault")) {
+ event.reply("https://www.spigotmc.org/resources/vault.34315/").queue();
+ }
+ if (topic.equalsIgnoreCase("PlaceholderAPI")) {
+ event.reply("https://www.spigotmc.org/resources/placeholderapi.6245/").queue();
+ }
+ if (topic.equalsIgnoreCase("ProtocolLib")) {
+ event.reply("https://www.spigotmc.org/resources/protocollib.1997/").queue();
+ }
+ if (topic.equalsIgnoreCase("TAB")) {
+ event.reply("https://github.com/NEZNAMY/TAB").queue();
+ }
+ if (topic.equalsIgnoreCase("NametagEdit")) {
+ event.reply("https://github.com/NEZNAMY/TAB").queue();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/common/PreorderCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/PreorderCommand.java
new file mode 100644
index 00000000..c6145e39
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/PreorderCommand.java
@@ -0,0 +1,107 @@
+package me.techscode.techdiscordbot.commands.common;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.database.TranscriptDatabase;
+import me.techscode.techdiscordbot.database.entities.SqlPreorder;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+import java.awt.*;
+import java.util.List;
+import java.util.Objects;
+
+public class PreorderCommand extends SimpleSlashCommand {
+
+ public PreorderCommand() {
+ super("preorder");
+ description("Check if you have pre-ordered Insane Vaults.");
+
+ mainGuildOnly();
+
+ options(
+ new OptionData(OptionType.STRING, "type", "What do you need?", true).addChoice("Check", "check").addChoice("Link", "link"),
+ new OptionData(OptionType.USER, "user", "The user to check the pre-order of.", false)
+ );
+ }
+
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+/*
+ final String type = event.getOption("type").getAsString();
+
+ if (type.equals("check")) {
+ final User user = Objects.requireNonNull(event.getOption("user")).getAsUser();
+
+ if (!SimpleRoles.hasRole(getMember(), Settings.Roles.staff)) {
+ final List sqLPreorder = TranscriptDatabase.PREORDERS.get(getMember().getIdLong());
+
+ for (final SqlPreorder sqlPreorder : sqLPreorder) {
+ if (sqlPreorder.getDiscordId() == getMember().getIdLong() && !sqlPreorder.getTransactionId().equalsIgnoreCase("none")) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Insane Vaults Preorder")
+ .text(
+ "**" + user.getAsMention() + " You have preorderd Insane Vaults!**",
+ "",
+ "You can access <#1058612057576054864> for your support questions.",
+ "To download the latest build of Insane Vaults go to the preorder page **[HERE](https://preorder.insanevaults.com/)**"
+ )
+ .color(Color.getColor("#e74c3c"))
+ .thumbnail("https://cloud.techscode.com/s/J6SaqeQRrErQwft/preview")
+ .build()
+ ).setEphemeral(true).queue();
+ } else {
+ event.replyEmbeds(new SimpleEmbedBuilder("Insane Vaults Preorder")
+ .text(
+ "**" + user.getAsMention() + " You haven't yet preorderd Insane Vaults!**",
+ "",
+ "You can preorder Insane Vaults **[HERE](https://preorder.insanevaults.com/)**"
+ )
+ .color(Color.getColor("#e74c3c"))
+ .thumbnail("https://cloud.techscode.com/s/J6SaqeQRrErQwft/preview")
+ .build()
+ ).setEphemeral(true).queue();
+ }
+ }
+ } else {
+ final List sqLPreorder = TranscriptDatabase.PREORDERS.get(user.getIdLong());
+
+ for (final SqlPreorder sqlPreorder : sqLPreorder) {
+ if (sqlPreorder.getDiscordId() == user.getIdLong() && !sqlPreorder.getTransactionId().equalsIgnoreCase("none")) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Insane Vaults Preorder")
+ .text(
+ TechDiscordBot.getJDA().getUserById(sqlPreorder.getDiscordId()).getAsMention() + " has pre-ordered Insane Vaults!",
+ "",
+ "Transaction ID; " + sqlPreorder.getTransactionId()
+ )
+ .color(Color.getColor("#e74c3c"))
+ .thumbnail("https://cloud.techscode.com/s/J6SaqeQRrErQwft/preview")
+ .build()
+ ).setEphemeral(true).queue();
+ } else {
+ event.replyEmbeds(new SimpleEmbedBuilder("Insane Vaults Preorder")
+ .text(
+ TechDiscordBot.getJDA().getUserById(sqlPreorder.getDiscordId()).getAsMention() + " has not pre-ordered Insane Vaults!",
+ "",
+ "Transaction ID; " + sqlPreorder.getTransactionId()
+ )
+ .color(Color.getColor("#e74c3c"))
+ .thumbnail("https://cloud.techscode.com/s/J6SaqeQRrErQwft/preview")
+ .build()
+ ).setEphemeral(true).queue();
+ }
+ }
+ }
+ }
+ if (type.equals("link")) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Preorder link")
+ .text("Pre-order here: https://preorder.insanevaults.com/")
+ .success().build()
+ ).setEphemeral(true).queue();
+ }*/
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/common/RemindCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/RemindCommand.java
new file mode 100644
index 00000000..8a389088
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/RemindCommand.java
@@ -0,0 +1,66 @@
+package me.techscode.techdiscordbot.commands.common;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.model.reminders.Reminder;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+import java.text.SimpleDateFormat;
+import java.util.Objects;
+
+/**
+ * TODO: Fix all the commands and finish this file!
+ */
+public class RemindCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public RemindCommand() {
+ super("remindme");
+ description("Get reminded about something.");
+
+ mainGuildOnly();
+
+ options(
+ new OptionData(OptionType.STRING, "time", "How long FROM NOW to be reminded.", true),
+ new OptionData(OptionType.STRING, "reminder", "What to be reminded about.", true),
+ new OptionData(OptionType.BOOLEAN, "private", "Whether to send the reminder in a dm or not.", false)
+ );
+ }
+
+ /**
+ * The main code of the timeout command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ final String time = event.getOption("time").getAsString();
+ final String message = event.getOption("reminder").getAsString();
+ final Boolean isPrivate = event.getOption("private") != null && event.getOption("private").getAsBoolean();
+
+ final Reminder reminder = TechDiscordBot.getRemindersManager().createReminder(event.getUser(), time, message, event.getChannel().asTextChannel(), isPrivate);
+
+ if (reminder == null) {
+ event.replyEmbeds(
+ new SimpleEmbedBuilder("Reminder - Error")
+ .text("An error has occurred. Did you specify a time and a reason?\n\n**Here are some examples!**:\n`/remind 1 day Fix x thing.`\n`/remind 30 hours I need help.`\n`/remind 30 hours I need help. dm` (makes it a dm)")
+ .error()
+ .build()
+ ).setEphemeral(true).queue();
+ } else {
+ event.replyEmbeds(
+ new SimpleEmbedBuilder("Reminder Set!")
+ .text("I will remind you for **" + reminder.getReminder() + "**!")
+ .success()
+ .build()
+ ).setEphemeral(true).queue();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/common/SubVerifyCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/SubVerifyCommand.java
new file mode 100644
index 00000000..782c77b5
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/SubVerifyCommand.java
@@ -0,0 +1,21 @@
+package me.techscode.techdiscordbot.commands.common;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+public class SubVerifyCommand extends SimpleSlashCommand {
+
+ public SubVerifyCommand() {
+ super("subverify");
+ description("Verify another person under your account.");
+
+ options(new OptionData(OptionType.USER, "user", "The user to add to your account.", true));
+ }
+
+ @Override
+ protected void onCommand(SlashCommandInteractionEvent event) {
+
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/common/WikiCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/WikiCommand.java
new file mode 100644
index 00000000..6e24a6c3
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/common/WikiCommand.java
@@ -0,0 +1,100 @@
+package me.techscode.techdiscordbot.commands.common;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.model.enums.Plugin;
+import net.dv8tion.jda.api.entities.channel.Channel;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+
+import java.awt.*;
+
+public class WikiCommand extends SimpleSlashCommand {
+
+ public WikiCommand() {
+ super("wiki");
+ description("Get a wiki link for a plugin");
+ }
+
+ @Override
+ protected void onCommand(SlashCommandInteractionEvent event) {
+
+ Channel channel = event.getChannel();
+
+ SimpleEmbedBuilder embedBuilder = new SimpleEmbedBuilder("📖 | Wiki");
+
+
+ switch (channel.getId()) {
+ // Permissions
+ case "330053303050436608" -> event.replyEmbeds(embedBuilder.text("Here is the Ultra Permissions wiki",
+ Plugin.ULTRA_PERMISSIONS.getEmojiRaw() + " https://ultrapermissions.com/wiki")
+ .color(Plugin.ULTRA_PERMISSIONS.getRole().getColor())
+ .build()).queue();
+
+ // Scoreboards
+ case "858052621574078474" -> event.replyEmbeds(embedBuilder.text("Here is the Ultra Scoreboards wiki",
+ Plugin.ULTRA_SCOREBOARDS.getEmojiRaw() + " https://ultrascoreboards.com/wiki")
+ .color(Plugin.ULTRA_SCOREBOARDS.getRole().getColor())
+ .build()).queue();
+
+ // Punishments
+ case "531251918291599401" -> event.replyEmbeds(embedBuilder.text("Here is the Ultra Punishments wiki",
+ Plugin.ULTRA_PUNISHMENTS.getEmojiRaw() + " https://ultrapunishments.com/wiki")
+ .color(Plugin.ULTRA_PUNISHMENTS.getRole().getColor())
+ .build()).queue();
+
+ // Customizer
+ case "380133603683860480" -> event.replyEmbeds(embedBuilder.text("Here is the Ultra Customizer wiki",
+ Plugin.ULTRA_CUSTOMIZER.getEmojiRaw() + " https://ultracustomizer.com/wiki")
+ .color(Plugin.ULTRA_CUSTOMIZER.getRole().getColor())
+ .build()).queue();
+
+ // Economy
+ case "737773631198986240" -> event.replyEmbeds(embedBuilder.text("Here is the Ultra Economy wiki",
+ Plugin.ULTRA_ECONOMY.getEmojiRaw() + " https://ultraeconomy.com/wiki")
+ .color(Plugin.ULTRA_ECONOMY.getRole().getColor())
+ .build()).queue();
+
+ // Regions
+ case "465975795433734155" -> event.replyEmbeds(embedBuilder.text("Here is the Ultra Regions wiki",
+ Plugin.ULTRA_REGIONS.getEmojiRaw() + " https://ultraregions.com/wiki")
+ .color(Plugin.ULTRA_REGIONS.getRole().getColor())
+ .build()).queue();
+
+ // MOTD
+ case "931264562995540038" -> event.replyEmbeds(embedBuilder.text("Here is the Ultra MOTD wiki",
+ Plugin.ULTRA_MOTD.getEmojiRaw() + " https://ultramotd.com/wiki")
+ .color(Plugin.ULTRA_MOTD.getRole().getColor())
+ .build()).queue();
+
+ // Shops
+ case "576813543698202624" -> event.replyEmbeds(embedBuilder.text("Here is the Insane Shops wiki",
+ Plugin.INSANE_SHOPS.getEmojiRaw() + " https://insaneshops.com/wiki")
+ .color(Plugin.INSANE_SHOPS.getRole().getColor())
+ .build()).queue();
+
+ // Vaults
+ case "1058612057576054864" -> event.replyEmbeds(embedBuilder.text("Here is the Insane Vaults wiki",
+ Plugin.INSANE_VAULTS.getEmojiRaw() + " https://insanevaults.com/wiki")
+ .color(Plugin.INSANE_VAULTS.getRole().getColor())
+ .build()).queue();
+ default -> event.replyEmbeds(new SimpleEmbedBuilder("📚 | Wiki")
+ .text("Showing all wiki's")
+ .field(
+ "Wiki's",
+ Plugin.ULTRA_PERMISSIONS.getEmojiRaw() + " https://ultrapermissions.com/wiki\n" +
+ Plugin.ULTRA_CUSTOMIZER.getEmojiRaw() + " https://ultracustomizer.com/wiki\n" +
+ Plugin.ULTRA_ECONOMY.getEmojiRaw() + " https://ultraeconomy.com/wiki\n" +
+ Plugin.ULTRA_REGIONS.getEmojiRaw() + " https://ultraregions.com/wiki\n" +
+ Plugin.ULTRA_PUNISHMENTS.getEmojiRaw() + " https://ultrapunishments.com/wiki\n" +
+ Plugin.ULTRA_SCOREBOARDS.getEmojiRaw() + " https://ultrascoreboards.com/wiki\n" +
+ Plugin.ULTRA_MOTD.getEmojiRaw() + " https://ultramotd.com/wiki\n" +
+ Plugin.INSANE_VAULTS.getEmojiRaw() + " https://insanevaults.com/wiki\n" +
+ Plugin.INSANE_SHOPS.getEmojiRaw() + " https://insaneshops.com/wiki\n" +
+ Plugin.INSANE_ANNOUNCER.getEmojiRaw() + " https://insaneannouncer.com/wiki\n",
+ false
+ )
+ .build()
+ ).queue();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/console/SayConsoleCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/console/SayConsoleCommand.java
new file mode 100644
index 00000000..6fb0cf6f
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/console/SayConsoleCommand.java
@@ -0,0 +1,39 @@
+package me.techscode.techdiscordbot.commands.console;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.handlers.console.SimpleConsoleCommand;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+
+import java.util.List;
+
+public class SayConsoleCommand extends SimpleConsoleCommand {
+ public SayConsoleCommand() {
+ super("say");
+ description("Says something from the console to an specific channel");
+ usage("say ");
+ }
+
+ @Override
+ public void onConsoleCommand(List args) {
+ if (args.isEmpty() || args.size() < 2) {
+ sendUsage();
+ return;
+ }
+
+ String channelId = args.get(0);
+ String message = String.join(" ", args.subList(1, args.size()));
+
+ TextChannel textChannel = TechDiscordBot.getMainGuild().getTextChannelById(channelId);
+
+ if (textChannel == null) {
+ Common.error("Channel not found!");
+ sendUsage();
+ return;
+ }
+
+ textChannel.sendMessage(message).queue();
+ Common.log("Message sent to " + textChannel.getName() + ": " + message);
+
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/debug/DatabaseCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/debug/DatabaseCommand.java
new file mode 100644
index 00000000..a05bfb1c
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/debug/DatabaseCommand.java
@@ -0,0 +1,109 @@
+package me.techscode.techdiscordbot.commands.debug;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.entities.SqlMember;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData;
+
+import java.util.List;
+
+public class DatabaseCommand extends SimpleSlashCommand {
+
+
+ public DatabaseCommand() {
+ super("database");
+ description("Test the database connection, outputs and more.");
+
+ mainGuildOnly();
+
+ subcommandGroup(new SubcommandGroupData("debug", "Debug some things from the database").addSubcommands(
+ new SubcommandData("member", "Check the database connection").addOption(OptionType.MENTIONABLE, "member", "The user to check", true),
+ new SubcommandData("verification", "Check the verification of a user").addOption(OptionType.MENTIONABLE, "member", "The user to check", true)
+ )
+ );
+
+ subCommands(
+ new SubcommandData("import", "Import all members from the guild to the database")
+ );
+
+ }
+
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ if (event.getSubcommandGroup().equals("debug")) {
+ switch (event.getSubcommandName()) {
+ case "member":
+ Member member = event.getOption("member").getAsMember();
+ final List sqlMemberList = Database.MEMBERSTable.getFromDiscordId(member.getIdLong());
+ for (final SqlMember sqlMember : sqlMemberList) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Database check")
+ .text("Success fully retrieved the member " + sqlMember.getDiscordMember().getAsMention() + " from the database.")
+ .field("ID: ", String.valueOf(sqlMember.getDiscordId()), true)
+ .field("Table ID:", String.valueOf(sqlMember.getId()), true)
+ .success().build()
+ ).setEphemeral(true).queue();
+ }
+ return;
+ case "verification":
+
+ }
+ }
+ switch (event.getSubcommandName()) {
+ case "import":
+ event.replyEmbeds(new SimpleEmbedBuilder("Database import")
+ .text("Importing all members from the guild to the database.")
+ .thumbnail("https://i.imgur.com/jcuD6gb.gif")
+ .build()
+ ).setEphemeral(true).queue();
+
+
+ final Thread thread = new Thread(() -> {
+ event.getGuild().loadMembers().onSuccess(members -> {
+ int numInteractions = members.size() +1;
+ int i = 0;
+ for (final Member member : members) {
+
+ if (Database.MEMBERSTable.getFromDiscordId(member.getIdLong()).isEmpty()) {
+ event.getHook().editOriginalEmbeds(new SimpleEmbedBuilder("Database import")
+ .text("Importing all members from the guild to the database.")
+ .thumbnail("https://i.imgur.com/jcuD6gb.gif")
+ .build()
+ ).queue();
+
+ Database.MEMBERSTable.add(new SqlMember(member.getIdLong()));
+ Common.log("Imported " + member.getUser().getAsTag() + " to the database.");
+ } else {
+ Common.log("Skipped " + member.getUser().getAsTag() + " because it's already in the database.");
+ }
+
+ if (i % 10 == 0) {
+ event.getHook().editOriginalEmbeds(new SimpleEmbedBuilder("Database import")
+ .text("Importing all members from the guild to the database.", "Progress: " + i + "/" + members.size())
+ .thumbnail("https://i.imgur.com/jcuD6gb.gif")
+ .build()
+ ).queue();
+ }
+
+ i++;
+ }
+ Common.log("Finished importing all members from the guild to the database.");
+
+ if (i == members.size()) {
+ event.getHook().editOriginalEmbeds(new SimpleEmbedBuilder("Database import")
+ .text("All members have been imported.")
+ .success().build()
+ ).queue();
+ }
+ });
+ });
+ thread.setName("DatabaseCommand-" + getUser().getId());
+ thread.start();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/BotCommands.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/BotCommands.java
new file mode 100644
index 00000000..ff0f74a0
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/BotCommands.java
@@ -0,0 +1,142 @@
+package me.techscode.techdiscordbot.commands.staff;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.actions.buttons.BotActionButtons;
+import me.techscode.techdiscordbot.modules.ApplyModule;
+import me.techscode.techdiscordbot.modules.TicketModule;
+import me.techscode.techdiscordbot.modules.VerificationModule;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+public class BotCommands extends SimpleSlashCommand {
+
+ public BotCommands() {
+ super("manage");
+ description("manage some things in the bot");
+
+ subCommands(
+ new SubcommandData("restart", "restart the bot"),
+ /*new SubcommandData("shutdown", "shutdown the bot"),*/
+ new SubcommandData("embeds", "manage embeds")
+ .addOptions(
+ new OptionData(OptionType.STRING, "type", "the type of embed", true)
+ .addChoice("overview", "overview")
+ .addChoice("ticket", "ticket")
+ .addChoice("application", "application")
+ .addChoice("verification", "verification"),
+ new OptionData(OptionType.STRING, "action", "the action to perform", true)
+ .addChoice("send", "send")
+ .addChoice("resend", "resend")
+ .addChoice("remove", "remove")
+ )
+ );
+
+
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onCommand(SlashCommandInteractionEvent event) {
+ String subCommand = event.getSubcommandName();
+
+ switch (Objects.requireNonNull(subCommand)) {
+ case "restart" -> {
+ event.replyEmbeds(new SimpleEmbedBuilder("Restart")
+ .text("To restart the bot you need to to confirm you want to restart the bot. To do this, press the Confirm button below.")
+ .error().build()).addActionRow(new BotActionButtons.shutdown().build()).setEphemeral(true).queue();
+ TechDiscordBot.getInstance().stop();
+ }
+ case "shutdown" -> event.replyEmbeds(new SimpleEmbedBuilder("Shutdown")
+ .text("To shutdown the bot you need to to confirm you want to stop the bot. To do this, press the Confirm button below.")
+ .error().build()).addActionRow(new BotActionButtons.shutdown().build()).setEphemeral(true).queue();
+ case "embeds" -> {
+ String type = Objects.requireNonNull(event.getOption("type")).getAsString();
+ String action = Objects.requireNonNull(event.getOption("action")).getAsString();
+
+
+ SimpleEmbedBuilder embed = new SimpleEmbedBuilder("Embeds").success();
+ TextChannel channel;
+ switch (type) {
+ case "overview":
+ break;
+ case "ticket":
+ channel = event.getJDA().getTextChannelById(Settings.Modules.Ticket.channel);
+ assert channel != null;
+ switch (action) {
+ case "send" -> {
+ TicketModule.embed();
+ embed.text("The embed has been sent.",
+ channel.getAsMention());
+ }
+ case "resend" -> {
+ channel.getIterableHistory().takeAsync(10).thenAccept(channel::purgeMessages);
+ TicketModule.embed();
+ embed.text("The embed has been resent.",
+ channel.getAsMention());
+ }
+ case "remove" -> {
+ channel.getIterableHistory().takeAsync(10).thenAccept(channel::purgeMessages);
+ embed.text("The embed has been removed.",
+ channel.getAsMention());
+ }
+ }
+ break;
+ case "application":
+ channel = event.getJDA().getTextChannelById(Settings.Modules.Apply.channel);
+ assert channel != null;
+ switch (action) {
+ case "send" -> {
+ ApplyModule.embed();
+ embed.text("The embed has been sent.",
+ channel.getAsMention());
+ }
+ case "resend" -> {
+ channel.getIterableHistory().takeAsync(10).thenAccept(channel::purgeMessages);
+ ApplyModule.embed();
+ embed.text("The embed has been resent.",
+ channel.getAsMention());
+ }
+ case "remove" -> {
+ channel.getIterableHistory().takeAsync(10).thenAccept(channel::purgeMessages);
+ embed.text("The embed has been removed.",
+ channel.getAsMention());
+ }
+ }
+ break;
+ case "verification":
+ channel = event.getJDA().getTextChannelById(Settings.Modules.Verification.channel);
+ assert channel != null;
+ switch (action) {
+ case "send" -> {
+ VerificationModule.embed();
+ embed.text("The embed has been sent.",
+ channel.getAsMention());
+ }
+ case "resend" -> {
+ channel.getIterableHistory().takeAsync(10).thenAccept(channel::purgeMessages);
+ VerificationModule.embed();
+ embed.text("The embed has been resent.",
+ channel.getAsMention());
+ }
+ case "remove" -> {
+ channel.getIterableHistory().takeAsync(10).thenAccept(channel::purgeMessages);
+ embed.text("The embed has been removed.",
+ channel.getAsMention());
+ }
+ }
+ break;
+ }
+ event.replyEmbeds(embed.build()).setEphemeral(true).queue();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/PruneCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/PruneCommand.java
new file mode 100644
index 00000000..c841e0fb
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/PruneCommand.java
@@ -0,0 +1,123 @@
+package me.techscode.techdiscordbot.commands.staff;
+
+import com.greazi.discordbotfoundation.handlers.buttons.SimpleButton;
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import net.dv8tion.jda.api.entities.*;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class PruneCommand extends SimpleSlashCommand {
+
+ public PruneCommand() {
+ super("clear");
+ description("Clear a certain amount of messages");
+
+ options(
+ new OptionData(OptionType.INTEGER, "amount", "The number of messages to clear", true),
+ new OptionData(OptionType.CHANNEL, "channel", "The channel to delete messages from", false)
+ );
+ }
+
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ // Get the command sender
+ final User executor = event.getUser();
+
+ // Get the guild from the event
+ final Guild guild = event.getGuild();
+ assert guild != null;
+
+ final int amount = event.getOption("amount").getAsInt();
+ final TextChannel channel = event.getOption("channel").getAsChannel().asTextChannel();
+
+
+ final List messages = channel.getHistory().retrievePast(amount).complete();
+
+ event.reply("**This will delete " + amount + " messages.**\nAre you sure?")
+ .addActionRow(
+ new ConfirmButton(executor.getId(), amount).build(),
+ new CancelButton(executor.getId()).build()
+ ).queue();
+ }
+
+ /**
+ * The prune confirm button
+ */
+ public static class ConfirmButton extends SimpleButton {
+
+ /**
+ * Set the button details
+ */
+ public ConfirmButton(final String userId, final int amount) {
+ super(userId + ":prune:" + amount);
+ label("Confirm");
+ buttonStyle(ButtonStyle.SUCCESS);
+ disabled(false);
+ }
+
+ /**
+ * The execution once the button has been pressed
+ *
+ * @param event ButtonInteractionEvent
+ */
+ @Override
+ protected void onButtonInteract(@NotNull final ButtonInteractionEvent event) {
+ final String[] id = event.getComponentId().split(":");
+
+ final String authorId = id[0];
+ final int amount = Integer.parseInt(id[2]);
+
+ if (!authorId.equals(event.getUser().getId()))
+ return;
+
+ final MessageChannel channel = event.getChannel();
+ event.deferEdit().queue();
+
+ event.getChannel().getIterableHistory()
+ .skipTo(event.getMessageIdLong())
+ .takeAsync(amount)
+ .thenAccept(channel::purgeMessages);
+ }
+ }
+
+ /**
+ * The prune cancel button
+ */
+ public static class CancelButton extends SimpleButton {
+
+ /**
+ * Set the button details
+ */
+ public CancelButton(final String userId) {
+ super(userId + ":cancelprune");
+ label("Cancel");
+ buttonStyle(ButtonStyle.DANGER);
+ disabled(false);
+ }
+
+ /**
+ * The execution once the button has been pressed
+ *
+ * @param event ButtonInteractionEvent
+ */
+ @Override
+ protected void onButtonInteract(@NotNull final ButtonInteractionEvent event) {
+ final String[] id = event.getComponentId().split(":");
+
+ final String authorId = id[0];
+
+ if (!authorId.equals(event.getUser().getId()))
+ return;
+
+ event.getHook().deleteOriginal().queue();
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/QuestionCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/QuestionCommand.java
new file mode 100644
index 00000000..840b910a
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/QuestionCommand.java
@@ -0,0 +1,192 @@
+package me.techscode.techdiscordbot.commands.staff;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.entities.SqlMember;
+import me.techscode.techdiscordbot.database.entities.SqlTicket;
+import me.techscode.techdiscordbot.modules.TicketModule;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionMapping;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData;
+
+import java.util.List;
+import java.util.Objects;
+
+public class QuestionCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public QuestionCommand() {
+ super("q");
+ description("give pre made answers and questions");
+
+ mainGuildOnly();
+
+ subcommandGroup(new SubcommandGroupData("ticket", "ticket answers and questions")
+ .addSubcommands(new SubcommandData("unverified", "Unverified premium plugin support ticket").addOption(OptionType.USER, "user", "The user that needs to be pinged", true))
+ .addSubcommands(new SubcommandData("close", "Ask the owner if the ticket can be closed")),
+ new SubcommandGroupData("spark", "spark answers and questions")
+ .addSubcommands(new SubcommandData("info", "Give information about spark").addOption(OptionType.USER, "user", "The user that needs this info", false))
+ .addSubcommands(new SubcommandData("report", "Ask for a spark report")
+ .addOptions(
+ new OptionData(OptionType.STRING, "type", "The type of report you want to ask for", true)
+ .addChoice("profiler", "profiler")
+ .addChoice("health", "health")
+ .addChoice("tickmonitor", "tickmonitor")
+ .addChoice("garbagecollection", "garbagecollection")
+ .addChoice("heapsummary", "heapsummary")
+ .addChoice("heapdump", "heapdump")
+ )
+ .addOption(OptionType.USER, "user", "The user you want to ask for a spark report", false))
+ );
+ }
+
+ /**
+ * The main code of the timeout command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+
+
+ if (event.getSubcommandGroup().equals("ticket")) {
+ switch (Objects.requireNonNull(event.getSubcommandName())) {
+ case "unverified" -> {
+ event.reply("success").queue(message -> message.deleteOriginal().queue());
+ event.getMessageChannel().sendMessage(event.getOption("user").getAsUser().getAsMention()).addEmbeds(
+ new SimpleEmbedBuilder("Premium plugin support")
+ .text(
+ "Hi there,",
+ "",
+ "It seems that you are trying to make a support ticket for a premium plugin, but you are not verified.",
+ "In order to get verified, you need to verify your purchase in <#907349490556616745>",
+ "Once you are verified, you will be able to make support tickets for premium plugins.",
+ "",
+ "If you have already send a verification request, please wait for a staff member to verify your purchase.",
+ "",
+ "If you have a pre sale question go to <#916558825367158794>",
+ "",
+ "This ticket will be closed in 1 hour."
+ ).build()
+ ).queue();
+ TicketModule.ticketClose(event.getOption("user").getAsMember(), Database.TICKETS.get(event.getChannel().getIdLong()).get(0), event.getTimeCreated().toEpochSecond(), "For pre sale question go to <#916558825367158794>, for verifying purchases go to <#907349490556616745>", 3600000);
+ }
+ case "close" -> {
+ event.reply("success").queue(message -> message.deleteOriginal().queue());
+ long channelId = event.getChannel().getIdLong();
+ List sqlTickets = Database.TICKETS.get(channelId);
+ if (sqlTickets.size() == 0) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Further assistance")
+ .text(
+ "Hi there,",
+ "",
+ "We would like to know if we can close this ticket.",
+ "If you need further assistance, please reply to this message.",
+ "",
+ "This ticket will be closed in 24 hours if no reply is given."
+ )
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+ SqlMember sqlMember = sqlTickets.get(0).getMember();
+ event.getMessageChannel().sendMessage(sqlMember.getDiscordMember().getAsMention()).addEmbeds(
+ new SimpleEmbedBuilder("Further assistance")
+ .text(
+ "Hi there,",
+ "",
+ "We would like to know if we can close this ticket.",
+ "If you need further assistance, please reply to this message.",
+ "",
+ "This ticket will be closed in 24 hours if no reply is given."
+ ).build()
+ ).queue();
+ return;
+ }
+ }
+ }
+
+ if (event.getSubcommandGroup().equals("spark")) {
+ SimpleEmbedBuilder embed = new SimpleEmbedBuilder();
+
+ if (Objects.equals(event.getSubcommandName(), "info")) {
+ embed.setAuthor("⚡ Spark");
+ embed.text("Spark is a plugin that allows you to see what is happening on your server.",
+ "",
+ "You can find more information about Spark on [their website](https://spark.lucko.me).");
+ event.replyEmbeds(embed.build()).queue();
+ return;
+ }
+
+ if (Objects.equals(event.getSubcommandName(), "report")) {
+ switch (Objects.requireNonNull(event.getOption("type")).getAsString()) {
+ case "profiler" -> {
+ embed.setAuthor("⚡ Spark Profiler");
+ embed.text("It seems that we would like to receive a Spark report from your server.",
+ "",
+ "[Spark](https://spark.lucko.me) is a plugin that allows you to see what is happening on your server.")
+ .field("Create a Spark Profile", "To create a report you need to run `/spark profiler start`\nOnce you are ready to see the results use `/spark profiler stop` to view the end result.", false)
+ .field("How long should the Profile last?", "The longer the profile runs the more accurate the results will be.\nWe recommend running the profile for at least 30 minutes.", false);
+ }
+ case "health" -> {
+ embed.setAuthor("⚡ Spark Health");
+ embed.text("It seems that we would like a Spark Health report from your server.",
+ "",
+ "[Spark](https://spark.lucko.me) is a plugin that allows you to see what is happening on your server.")
+ .field("Create a Spark Health report", "To create a report you need to run `/spark health `.\nProvide this report and if needed the one down below.", false)
+ .field("Additional commands", "`/spark health --memory` is needed when there are memory issues.\n`/spark health --network` is needed when there are network issues.", false);
+ }
+ case "tickmonitor" -> {
+ embed.setAuthor("⚡ Spark Tick-monitor");
+ embed.text("We would like to investigate what is happening on your server if you are experiencing lag.",
+ "The Spark Tickmonitor is a tool that shows the duration of a tick as well as what occurs during a tick.",
+ "",
+ "[Spark](https://spark.lucko.me) is a plugin that allows you to see what is happening on your server.")
+ .field("Enable Tick-monitor", "To enable the Tickmonitor you need to run `/spark tickmonitor`. This commands toggles the status of the ticketmonitor.", false)
+ .field("Additional commands", "`/spark tickmonitor --threshold ` only reporting ticks which exceed a percentage increase from the average tick duration.\n`/spark tickmonitor --threshold-tick ` only reporting ticks which exceed the given duration in milliseconds.\n`/spark tickmonitor --without-gc` disable reports about GC activity.", false);
+ }
+ case "garbagecollection" -> {
+ embed.setAuthor("⚡ Spark Garbage Collection");
+ embed.text("It seems that we need to take a deeper look in your memory.",
+ "There for we are gonna take a look in your GC (Garbage Collection).",
+ "",
+ "[Spark](https://spark.lucko.me) is a plugin that allows you to see what is happening on your server.")
+ .field("Print GC", "To print your GC you need to run `/spark gc`", false)
+ .field("Monitor GC", "To activly view your GC you need to run `/spark gcmonitor`", false);
+ }
+ case "heapsummary" -> {
+ embed.setAuthor("⚡ Spark Heap summary");
+ embed.text("It seems that we need a better look at what is stored in your memory.",
+ "",
+ "[Spark](https://spark.lucko.me) is a plugin that allows you to see what is happening on your server.")
+ .field("Get Heapsummary", "To get a Heapsummary your need to run `/spark heapsummary` this returns a view with all data stored in its memory", false);
+ }
+ case "heapdump" -> {
+ embed.setAuthor("⚡ Spark Heapdump");
+ embed.text("Spark has an option to generates a new heapdump (.hprof snapshot) file and saves that heapdump to the disk.",
+ "**NOTE;** This require as much space as your available RAM!",
+ "",
+ "[Spark](https://spark.lucko.me) is a plugin that allows you to see what is happening on your server.")
+ .field("Create Heapdump", "To create a Heapdump run `/spark heapdump` this saves a file to your disk.", false)
+ .field("Additional commands", "`/spark heapdump --compress ` to specify that the heapdump should be compressed using the given type. The supported types are gzip, xz and lzma.", false);
+ }
+ }
+ }
+
+ OptionMapping user = event.getOption("user");
+ if (user == null) {
+ event.replyEmbeds(embed.build()).queue();
+ } else {
+ event.reply("<@" + user.getAsUser().getId() + ">").addEmbeds(embed.build()).queue();
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/RoleCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/RoleCommand.java
new file mode 100644
index 00000000..0b97abac
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/RoleCommand.java
@@ -0,0 +1,81 @@
+package me.techscode.techdiscordbot.commands.staff;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.handlers.selectmenu.string.SimpleStringSelectMenu;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.actions.menus.RolesMenu;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+import net.dv8tion.jda.api.interactions.components.selections.StringSelectInteraction;
+
+/**
+ * TODO: Fix all the commands and finish this file!
+ */
+public class RoleCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public RoleCommand() {
+ super("role");
+ description("add roles to a user");
+
+ mainGuildOnly();
+
+ subCommands(
+ new SubcommandData("add", "add roles to a user").addOption(OptionType.USER, "user", "The user to add roles", true),
+ new SubcommandData("remove", "remove roles from a user").addOption(OptionType.USER, "user", "The user to remove roles", true)
+
+ );
+ options(new OptionData(OptionType.USER, "user", "The user to add roles", true));
+ }
+
+ /**
+ * The main code of the timeout command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ final User target = event.getOption("user").getAsUser();
+
+ // Get the guild where the command was executed
+ final Guild guild = event.getGuild();
+ assert guild != null;
+
+ // Get the member from the guild
+ final Member guildMember = guild.getMember(target);
+
+ if (guildMember == null) {
+ event.reply("The user is not in this guild.").setEphemeral(true).queue();
+ return;
+ }
+
+ switch (event.getSubcommandName()) {
+ case "add" -> event.replyEmbeds(
+ new SimpleEmbedBuilder("Add Roles")
+ .text("Select the roles you want to add to member " + guildMember.getAsMention() + ".")
+ .build()
+ )
+ .addActionRow(
+ new RolesMenu.Add(guildMember).build()
+ ).setEphemeral(true).queue();
+ case "remove" -> event.replyEmbeds(
+ new SimpleEmbedBuilder("Remove Roles")
+ .text("Select the roles you want to remove from member " + guildMember.getAsMention() + ".")
+ .build()
+ )
+ .addActionRow(
+ new RolesMenu.Remove(guildMember).build()
+ ).setEphemeral(true).queue();
+ }
+
+
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/UpdateCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/UpdateCommand.java
new file mode 100644
index 00000000..b6929f69
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/UpdateCommand.java
@@ -0,0 +1,56 @@
+package me.techscode.techdiscordbot.commands.staff;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.utils.Changelog;
+import net.dv8tion.jda.api.entities.channel.Channel;
+import net.dv8tion.jda.api.entities.channel.ChannelType;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionMapping;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+
+public class UpdateCommand extends SimpleSlashCommand {
+
+ public UpdateCommand() {
+ super("update");
+ description("Send an update embed to an channel");
+
+ OptionData optionData = new OptionData(OptionType.STRING, "version", "The version of the update", true);
+
+ for (Changelog changelog : Changelog.values()) {
+ optionData.addChoice(changelog.getVersion(), changelog.name());
+ }
+
+ options(
+ optionData,
+ new OptionData(OptionType.CHANNEL, "channel", "The channel to send the update to", false)
+
+ );
+
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onCommand(@NotNull SlashCommandInteractionEvent event) {
+ String version = Objects.requireNonNull(event.getOption("version")).getAsString();
+ OptionMapping channelOptionMapping = event.getOption("channel");
+
+ Changelog changelog = Changelog.valueOf(version);
+
+ SimpleEmbedBuilder embed = new SimpleEmbedBuilder("Update " + changelog.getVersion())
+ .field("Changes:", "- " + String.join("\n- ", changelog.getChanges()), false);
+
+ if (channelOptionMapping == null) {
+ event.replyEmbeds(embed.build()).setEphemeral(true).queue();
+ } else {
+ channelOptionMapping.getAsChannel().asTextChannel().sendMessageEmbeds(embed.build()).queue();
+ }
+
+
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/UserInfoCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/UserInfoCommand.java
new file mode 100644
index 00000000..1bdd6091
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/UserInfoCommand.java
@@ -0,0 +1,55 @@
+package me.techscode.techdiscordbot.commands.staff;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+import java.time.format.DateTimeFormatter;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * The mute command to mute an player
+ */
+public class UserInfoCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public UserInfoCommand() {
+ super("info");
+ description("Get information about a specific user.");
+
+ mainGuildOnly();
+
+ options(new OptionData(OptionType.USER, "member", "The member that needs a timeout", true));
+ }
+
+ /**
+ * The main code of the timeout command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ final Member member = event.getOption("member") == null ? event.getMember() : Objects.requireNonNull(event.getOption("member")).getAsMember();
+ assert member != null;
+ final User user = member.getUser();
+
+ event.replyEmbeds(
+ new SimpleEmbedBuilder(user.getName() + "#" + user.getDiscriminator())
+ .field("ID", user.getId(), true)
+ .field("Status", member.getOnlineStatus().getKey().substring(0, 1).toUpperCase() + member.getOnlineStatus().getKey().substring(1), true)
+ .field("Times", "Created: " + user.getTimeCreated().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")) + ", Joined: " + member.getTimeJoined().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")), true)
+ .field("Flags", user.getFlags().clone().stream().map(User.UserFlag::getName).collect(Collectors.joining(", ")), true)
+ .field("Roles", member.getRoles().stream().map(Role::getAsMention).collect(Collectors.joining(", ")), true)
+ .thumbnail(user.getAvatarUrl())
+ .build()
+ ).queue();
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/BanCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/BanCommand.java
new file mode 100644
index 00000000..3f13cee0
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/BanCommand.java
@@ -0,0 +1,88 @@
+package me.techscode.techdiscordbot.commands.staff.punishment;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.model.Logs;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+import java.time.temporal.ChronoUnit;
+import java.util.concurrent.TimeUnit;
+
+public class BanCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the ban command with its specific settings
+ */
+ public BanCommand() {
+ super("ban");
+ description("Ban a person from the guild");
+
+ // Se the specific options that can be used for the command
+ options(
+ new OptionData(OptionType.USER, "user", "The user to ban", true),
+ new OptionData(OptionType.STRING, "reason", "The reason for the banning", true)
+ );
+ }
+
+ /**
+ * The main code of the ban command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ // Get the command sender
+ final User executor = event.getUser();
+
+ // Get the guild where the command was executed
+ final Guild guild = event.getGuild();
+ assert guild != null;
+
+ // Get the options from the command
+ final User target = event.getOption("user").getAsUser();
+ final String reason = event.getOption("reason").getAsString();
+
+ // Get the member from the guild
+ final Member guildMember = guild.getMember(target);
+
+ // Check if the target isn't null
+ if (guildMember == null) {
+ event.reply("The user is not in this guild.").setEphemeral(true).queue();
+ return;
+ }
+
+ // Check if the target is a staff member
+ if (SimpleRoles.hasRole(guildMember, "staff") || SimpleRoles.hasRole(guildMember, "Bot")) {
+ event.reply("You are not allowed to ban a staff member or a BOT").setEphemeral(true).queue();
+ return;
+ }
+
+ // Add a new ban to the guild's ban list
+ guild.ban(target, 1, TimeUnit.DAYS)
+ .reason(reason)
+ .queue();
+
+ SimpleEmbedBuilder embed = new SimpleEmbedBuilder("Ban | " + target.getName())
+ .text("Banned a user from the GUILD;")
+ .field("Target;", target.getAsMention(), true)
+ .field("Staff Member;", executor.getAsMention(), true)
+ .field("Reason;", reason, false)
+ .error();
+
+ // An extra check to see if the guild is really the main guild
+ if (guild == TechDiscordBot.getMainGuild()) {
+ Logs.PunishLogs.log(
+ embed
+ );
+ }
+
+ event.replyEmbeds(embed.build()).setEphemeral(true).queue();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/KickCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/KickCommand.java
new file mode 100644
index 00000000..0fcb03ac
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/KickCommand.java
@@ -0,0 +1,77 @@
+package me.techscode.techdiscordbot.commands.staff.punishment;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.model.Logs;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+public class KickCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the kick command with its specific settings
+ */
+ public KickCommand() {
+ super("kick");
+ description("Kick a user from the guild");
+
+ // Set the specific options that can be used for the command
+ options(
+ new OptionData(OptionType.USER, "user", "The user to kick", true),
+ new OptionData(OptionType.STRING, "reason", "The reason for the kicking", true)
+ );
+ }
+
+ /**
+ * The main code of the kick command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ // Get the command sender
+ final User executor = event.getUser();
+
+ // Get the guild from the event
+ final Guild guild = event.getGuild();
+ assert guild != null;
+
+ // Get the options from the command
+ final User target = event.getOption("user").getAsUser();
+ final String reason = event.getOption("reason").getAsString();
+
+ // Get the member from the guild
+ final Member guildMember = guild.getMember(target);
+
+ // Check if the target isn't null
+ if (guildMember == null) {
+ event.reply("The user is not in this guild.").setEphemeral(true).queue();
+ return;
+ }
+
+ // Check if the target is a staff member
+ if (guildMember.getRoles().contains(SimpleRoles.getRoleByName(getGuild(), "staff")) || guildMember.getRoles().contains(SimpleRoles.getRoleByName(getGuild(), "bot"))) {
+ event.reply("You are not allowed to kick a staff member or a BOT").setEphemeral(true).queue();
+ return;
+ }
+
+ // Kick the user from the guild
+ guild.kick(target, reason).queue();
+
+ if (guild == TechDiscordBot.getMainGuild()) {
+ Logs.PunishLogs.log(
+ new SimpleEmbedBuilder("Kick | " + target.getName())
+ .text("Kicked a user from the GUILD;")
+ .field("Target;", target.getAsMention(), true)
+ .field("Staff member;", executor.getAsMention(), true)
+ .field("Reason;", reason, false)
+ );
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/TimeoutCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/TimeoutCommand.java
new file mode 100644
index 00000000..98f59d45
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/TimeoutCommand.java
@@ -0,0 +1,143 @@
+package me.techscode.techdiscordbot.commands.staff.punishment;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.model.Logs;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * The mute command to mute an player
+ */
+public class TimeoutCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public TimeoutCommand() {
+ super("timeout");
+ description("Timeout a user");
+
+ mainGuildOnly();
+
+ // Set the options for the command
+ options(
+ new OptionData(OptionType.USER, "user", "The user to timeout", true),
+ new OptionData(OptionType.STRING, "duration", "The duration", true),
+ new OptionData(OptionType.STRING, "timeunit", "The time unit (s, h, d, w, m) of the timeout", true)
+ .addChoice("seconds", "s")
+ .addChoice("minutes", "m")
+ .addChoice("hours", "h")
+ .addChoice("days", "d")
+ .addChoice("weeks", "w")
+ .addChoice("months", "M"),
+ new OptionData(OptionType.STRING, "reason", "The reason for the timeout", true)
+ );
+ }
+
+ /**
+ * The main code of the timeout command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ // Get the command sender
+ final User executor = event.getUser();
+
+ // Get the guild from the event
+ final Guild guild = event.getGuild();
+ assert guild != null;
+
+ final User target = event.getOption("user").getAsUser();
+ final String duration = event.getOption("duration").getAsString();
+ final String timeunit = event.getOption("timeunit").getAsString();
+ final String reason = event.getOption("reason").getAsString();
+
+ // Get the member from the guild
+ final Member guildMember = guild.getMember(target);
+
+ // Check if the target isn't null
+ if (guildMember == null) {
+ event.reply("The user is not in this guild.").setEphemeral(true).queue();
+ return;
+ }
+
+ // Check if the target is a staff member
+ if (guildMember.getRoles().contains(SimpleRoles.getRoleByName(getGuild(), "staff")) || guildMember.getRoles().contains(SimpleRoles.getRoleByName(getGuild(), "bot"))) {
+ event.reply("You are not allowed to timeout a staff member or a BOT").setEphemeral(true).queue();
+ return;
+ }
+
+ // TODO: Fix this part to make it simpler
+
+ // Retrieve the time option of the command
+ long time = event.getOption("time").getAsLong();
+ final String timeUnitString = event.getOption("timeunit").getAsString();
+ TimeUnit timeUnit = null;
+
+ // Check the timeUnitsString to determine the duration
+ switch (timeUnitString) {
+ case "s":
+ timeUnit = TimeUnit.SECONDS;
+ break;
+ case "m":
+ timeUnit = TimeUnit.MINUTES;
+ break;
+ case "h":
+ timeUnit = TimeUnit.HOURS;
+ break;
+ case "d":
+ timeUnit = TimeUnit.DAYS;
+ break;
+ case "w":
+ timeUnit = TimeUnit.DAYS;
+ time = time * 7;
+ break;
+ case "M":
+ timeUnit = TimeUnit.DAYS;
+ time = time * 30;
+ break;
+ default:
+ event.replyEmbeds(new SimpleEmbedBuilder("timeout | ERROR")
+ .text("You did not fil in the right time unit")
+ .error().build()).setEphemeral(true).queue();
+ break;
+ }
+
+ // Assert the option to check if the values aren't null
+ assert timeUnit != null;
+
+ // Give the member a timeout
+ guild.getMember(target).timeoutFor(time, timeUnit).queue();
+
+ // Send success message the executor of the command
+ event.replyEmbeds(new SimpleEmbedBuilder("TimeOut | SUCCESS")
+ .text("You have given " + target.getAsMention() + " a timeout;",
+ "",
+ "**Reason:** " + reason,
+ "**Duration:** " + time + " " + timeUnit.toString().toLowerCase())
+ .build()).setEphemeral(true).queue();
+
+ // Send dm message to the member that got a timeout
+ target.openPrivateChannel().complete().sendMessageEmbeds(new SimpleEmbedBuilder("Timeout | RECEIVED")
+ .text("You have been given an timeout!",
+ "",
+ "**Reason:** " + reason,
+ "**Duration:** " + time + " " + timeUnit.toString().toLowerCase())
+ .build()).queue();
+
+ Logs.PunishLogs.log(new SimpleEmbedBuilder("Timeout | SUCCESS")
+ .text(target.getAsMention() + " has been given a timeout",
+ " ",
+ "**Reason:** " + reason,
+ "**Duration:** " + time + " " + timeUnit.toString().toLowerCase()));
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/WarnCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/WarnCommand.java
new file mode 100644
index 00000000..86353da9
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/staff/punishment/WarnCommand.java
@@ -0,0 +1,87 @@
+package me.techscode.techdiscordbot.commands.staff.punishment;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.model.Logs;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+
+/**
+ * TODO: Fix all the commands and finish this file!
+ */
+public class WarnCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public WarnCommand() {
+ super("warn");
+ description("Warn a user");
+
+ mainGuildOnly();
+
+ options(
+ new OptionData(OptionType.USER, "user", "The user to warn", true),
+ new OptionData(OptionType.STRING, "reason", "The reason for the warn", true)
+ );
+ }
+
+ /**
+ * The main code of the timeout command
+ *
+ * @param event SlashCommandInteractionEvent
+ */
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ // Get the command sender
+ final User executor = event.getUser();
+
+ // Get the guild from the event
+ final Guild guild = event.getGuild();
+ assert guild != null;
+
+ final User target = event.getOption("user").getAsUser();
+ final String reason = event.getOption("reason").getAsString();
+
+ // Get the member from the guild
+ final Member guildMember = guild.getMember(target);
+
+ // Check if the target isn't null
+ if (guildMember == null) {
+ event.reply("The user is not in this guild.").setEphemeral(true).queue();
+ return;
+ }
+
+ // Check if the target is a staff member
+ if (guildMember.getRoles().contains(SimpleRoles.getRoleByName(getGuild(), "staff")) || guildMember.getRoles().contains(SimpleRoles.getRoleByName(getGuild(), "bot"))) {
+ event.reply("You are not allowed to warn a staff member or a BOT").setEphemeral(true).queue();
+ return;
+ }
+
+ event.reply("You have warned; " + target.getAsMention() + " for; `" + reason + "`").queue();
+
+ event.getGuildChannel().sendMessageEmbeds(
+ new SimpleEmbedBuilder("Warning")
+ .text("You have been warned by; " + executor.getAsMention())
+ .field("Reason;", reason, false)
+ .build()
+ ).queue();
+
+ if (guild == TechDiscordBot.getMainGuild()) {
+ Logs.PunishLogs.log(
+ new SimpleEmbedBuilder("Warn | " + target.getName())
+ .text("Warned a user in the guild;")
+ .field("Target;", target.getAsMention(), true)
+ .field("Staff member;", executor.getAsMention(), true)
+ .field("Reason;", reason, false)
+ );
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/tickets/TicketCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/tickets/TicketCommand.java
new file mode 100644
index 00000000..be1206a4
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/tickets/TicketCommand.java
@@ -0,0 +1,112 @@
+package me.techscode.techdiscordbot.commands.tickets;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.entities.SqlTicket;
+import me.techscode.techdiscordbot.modules.TicketModule;
+import me.techscode.techdiscordbot.settings.Settings;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public class TicketCommand extends SimpleSlashCommand {
+
+ public TicketCommand() {
+ super("ticket");
+ description("Create a ticket");
+
+ mainGuildOnly();
+
+ subCommands(
+ new SubcommandData("create", "Create a ticket"),
+ new SubcommandData("close", "Close a ticket").addOption(OptionType.STRING, "reason", "The reason for closing the ticket", true)
+ );
+ }
+
+ @Override
+ protected void onCommand(SlashCommandInteractionEvent event) {
+
+ String subCommand = event.getSubcommandName();
+
+ assert subCommand != null;
+ if(subCommand.equals("create")) {
+ // Create the ticket channel
+ CompletableFuture future = TicketModule.ticketCreate(getMember(), getGuild(), getMember());
+
+ future.thenAccept(channel -> {
+ if (channel == null) {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Creation Failed")
+ .text(
+ "Your ticket could not be created.",
+ "You have reached the maximum amount of tickets you can create."
+ )
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+
+ // Send a message to the user
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Created")
+ .text(
+ "Your ticket has been created.",
+ "To complete the ticket creation process, please follow the steps in " + channel.getAsMention()
+ )
+ .success().build()).setEphemeral(true).queue();
+ });
+
+ } else if(subCommand.equals("close")) {
+ long channelId = event.getChannel().getIdLong();
+ List sqlTickets = Database.TICKETS.get(channelId);
+
+ if (sqlTickets.size() == 0) {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Not Found")
+ .text(
+ "This ticket does not exist in the database.",
+ "You will need to delete this ticket manually."
+ )
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+
+
+ String reason = event.getOption("reason").getAsString();
+ int length = reason.split(" ").length;
+
+ if (length < 3) {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Not Closed")
+ .text(
+ "You have filled in a reason that is too short.",
+ "Please provide a reason that is longer than 3 words.",
+ "",
+ "Example reason: 'Fixed Ultra Regions FLY flag not working correctly'"
+ )
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+
+ for (SqlTicket sqlTicket : sqlTickets) {
+ if (sqlTicket.getChannelId() != channelId) continue;
+
+ if (sqlTicket.getMember().getDiscordId() == event.getMember().getIdLong() || SimpleRoles.hasRole(event.getMember(), Settings.Roles.staff)) {
+ TicketModule.ticketClose(event.getMember(), sqlTicket, event.getTimeCreated().toEpochSecond(), reason, 30000);
+ event.reply("Ticket closed").setEphemeral(true).queue(message -> message.deleteOriginal().queue());
+ } else {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Not Closed")
+ .text(
+ "It seems that you are not the owner of this ticket.",
+ "Only the ticket owner can close the ticket.",
+ "",
+ "*If you think this is a mistake, please contact a staff member.*"
+ )
+ .error().build()).setEphemeral(true).queue();
+ }
+ return;
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/tickets/TicketStaffCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/tickets/TicketStaffCommand.java
new file mode 100644
index 00000000..0c4df80c
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/tickets/TicketStaffCommand.java
@@ -0,0 +1,390 @@
+package me.techscode.techdiscordbot.commands.tickets;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleRoles;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.TranscriptDatabase;
+import me.techscode.techdiscordbot.database.entities.SqlTicket;
+import me.techscode.techdiscordbot.database.entities.SqlTranscript;
+import me.techscode.techdiscordbot.model.Logs;
+import me.techscode.techdiscordbot.modules.TicketModule;
+import me.techscode.techdiscordbot.settings.Settings;
+import me.techscode.techdiscordbot.transcripts.TicketTranscript;
+import me.techscode.techdiscordbot.transcripts.TicketTranscriptOptions;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.IPermissionHolder;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionMapping;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public class TicketStaffCommand extends SimpleSlashCommand {
+
+ public TicketStaffCommand() {
+ super("ticketstaff");
+
+ description("Manage tickets");
+
+ mainGuildOnly();
+
+ subCommands(
+ new SubcommandData("create", "Create a ticket for a user").addOption(OptionType.USER, "user", "The user to create a ticket for", true),
+ new SubcommandData("add", "Add a user to a ticket").addOption(OptionType.USER, "user", "The user that needs to be added to the ticket", true),
+ new SubcommandData("remove", "Remove a user from a ticket").addOption(OptionType.USER, "user", "The user that needs to be removed to the ticket", true),
+ new SubcommandData("transcript", "Get a transcript of a ticket"),
+ new SubcommandData("list", "List all tickets"),
+ new SubcommandData("info", "Get information about a ticket"),
+ new SubcommandData("rename", "Rename a ticket"),
+ new SubcommandData("transfer", "Transfer a ticket to another category").addOptions(new OptionData(OptionType.STRING, "category", "The category to transfer the ticket to", true).addChoice("support", "support").addChoice("development", "development").addChoice("management", "management").addChoice("greazi", "greazi").addChoice("timo", "timo").addChoice("lucifer", "lucifer").addChoice("ghost", "ghost").addChoice("fabian", "fabian").addChoice("peng", "peng").addChoice("das", "das").addChoice("opti", "opti")),
+ new SubcommandData("archive", "Archive a ticket"),
+ new SubcommandData("unarchive", "Unarchive a ticket"),
+ new SubcommandData("delete", "Delete a ticket")
+ );
+ }
+
+ @Override
+ protected void onCommand(@NotNull final SlashCommandInteractionEvent event) {
+ final String subCommand = event.getSubcommandName();
+
+ assert subCommand != null;
+ if (subCommand.equals("create")) {
+ // Create the ticket channel
+ Member createMember = event.getOption("user").getAsMember();
+ CompletableFuture future = TicketModule.ticketCreate(event.getMember(), event.getGuild(), createMember);
+ future.thenAccept(channel -> {
+ if (channel == null) {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Creation Failed")
+ .text(
+ "Your ticket could not be created.",
+ "You have reached the maximum amount of tickets you can create."
+ )
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+
+ // Send a message to the user
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Created")
+ .text(
+ "A new ticket has been created for another user.",
+ "The other user will be able to follow the steps inside " + channel.getAsMention()
+ )
+ .success().build()).setEphemeral(true).queue();
+ event.getChannel().sendMessageEmbeds(new SimpleEmbedBuilder("Ticket Created")
+ .text(
+ createMember.getAsMention() + " there has been created a ticket for you.",
+ "Please follow the steps inside " + channel.getAsMention()
+ )
+ .success().build()).queue();
+ });
+ return;
+ }
+
+ TextChannel textChannel = event.getChannel().asTextChannel();
+
+ List sqlTickets = Database.TICKETS.get(textChannel.getIdLong());
+
+ if (sqlTickets.isEmpty()) {
+ event.replyEmbeds(new SimpleEmbedBuilder("📨 Ticket Not Found")
+ .text(
+ "This channel is not a ticket and can not be managed with this command.",
+ "If you think this is a mistake, please contact my developer."
+ )
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+
+ SqlTicket sqlTicket = null;
+ for (SqlTicket sqlTicket1 : sqlTickets) {
+ if (sqlTicket1.getChannelId() == textChannel.getIdLong()) sqlTicket = sqlTicket1;
+ }
+
+ switch (Objects.requireNonNull(subCommand)) {
+ case "add" -> {
+ if (event.getMember().getIdLong() == event.getOption("user").getAsUser().getIdLong()) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("You cannot add yourself to a ticket.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+ for (Member member : textChannel.getMembers()) {
+ if (member.getIdLong() == event.getOption("user").getAsUser().getIdLong()) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This user is already inside the ticket.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+ }
+ Member addMember = event.getOption("user").getAsMember();
+ final List permissionsAdd = new ArrayList<>(
+ Arrays.asList(
+ Permission.VIEW_CHANNEL,
+ Permission.MESSAGE_SEND,
+ Permission.MESSAGE_HISTORY,
+ Permission.MESSAGE_ATTACH_FILES,
+ Permission.MESSAGE_EMBED_LINKS,
+ Permission.MESSAGE_ADD_REACTION,
+ Permission.MANAGE_EMOJIS_AND_STICKERS
+ )
+ );
+ textChannel.getManager().putMemberPermissionOverride(addMember.getIdLong(), permissionsAdd, null).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully added " + addMember.getAsMention() + " to the ticket.")
+ .success().build()).setEphemeral(true).queue();
+ Logs.TicketLogs.log(new SimpleEmbedBuilder("Ticket Member Added")
+ .text(
+ "**Member:** " + addMember.getAsMention(),
+ "**Ticket:** " + textChannel.getName() + " (" + textChannel.getId() + ")"
+ )
+ );
+ return;
+ }
+ case "remove" -> {
+ if (event.getMember().getIdLong() == event.getOption("user").getAsUser().getIdLong()) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("You cannot remove yourself of a ticket.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+ if (sqlTicket.getMember().getDiscordId() == event.getOption("user").getAsUser().getIdLong()) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("You cannot remove the ticket owner from there own ticket.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+ for (Member member : textChannel.getMembers()) {
+ if (member.getIdLong() == event.getOption("user").getAsUser().getIdLong()) {
+ Member removeMember = event.getOption("user").getAsMember();
+
+ final List permissionsRemove = new ArrayList<>(
+ Arrays.asList(
+ Permission.VIEW_CHANNEL,
+ Permission.MESSAGE_SEND,
+ Permission.MESSAGE_HISTORY,
+ Permission.MESSAGE_ATTACH_FILES,
+ Permission.MESSAGE_EMBED_LINKS,
+ Permission.MESSAGE_ADD_REACTION,
+ Permission.MANAGE_EMOJIS_AND_STICKERS
+ )
+ );
+ textChannel.getManager().putMemberPermissionOverride(removeMember.getIdLong(), null, permissionsRemove).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully removed " + removeMember.getAsMention() + " from the ticket.")
+ .success().build()).setEphemeral(true).queue();
+
+ Logs.TicketLogs.log(new SimpleEmbedBuilder("Ticket Member Removed")
+ .text(
+ "**Member:** " + removeMember.getAsMention(),
+ "**Ticket:** " + textChannel.getName() + " (" + textChannel.getId() + ")"
+ )
+ );
+ return;
+ }
+ }
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This user is already removed from the ticket.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+ case "transcript" -> {
+ TicketTranscript transcript = TicketTranscript.buildTranscript(event.getChannel().asTextChannel(), TicketTranscriptOptions.DEFAULT);
+ SqlTicket finalSqlTicket = sqlTicket;
+ transcript.build(object -> {
+ assert finalSqlTicket != null;
+ if (finalSqlTicket.getMember().getDiscordMember() != null) {
+ Logs.TicketLogs.log(
+ new SimpleEmbedBuilder("Ticket Transcript (Command)")
+ .text("Transcript of " + event.getChannel().getAsMention() + ": " + transcript.getUrl())
+ .color(Color.ORANGE)
+ );
+ }
+
+ event.replyEmbeds(
+ new SimpleEmbedBuilder("Ticket Transcript")
+ .text("Transcript of " + event.getChannel().getAsMention() + ": " + transcript.getUrl())
+ .color(Color.ORANGE)
+ .build()
+ ).queue();
+
+ TranscriptDatabase.TRANSCRIPT.add(new SqlTranscript(object.get("id").getAsString(), object.toString()));
+ });
+ }
+ case "list" -> {
+ }
+ case "info" -> {
+ }
+ case "rename" -> {
+ }
+ case "transfer" -> {
+ OptionMapping optionMap = event.getOption("category");
+ if (optionMap == null) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("You need to provide a category.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ }
+ switch (optionMap.getAsString()) {
+ case "support" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.support) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the support category.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.support)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the support category.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "development" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.development) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the development category.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.development)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the development category.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "management" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.management) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the development category.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.management)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the development category.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "greazi" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.greazi) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the category for Greazi.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.greazi)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the category for Greazi.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "timo" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.timo) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the category for Timo.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.timo)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the category for Timo.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "lucifer" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.lucifer) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the category for Lucifer.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.lucifer)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the category for Lucifer.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "ghost" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.ghost) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the category for Ghost.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.ghost)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the category for Ghost.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "fabian" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.fabian) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the category for Fabian.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.fabian)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the category for Fabian.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "peng" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.peng) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the category for Peng.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.peng)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the category for Peng.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "das" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.das) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the category for Das.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.das)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the category for Das.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ case "opti" -> {
+ if (textChannel.getParentCategoryIdLong() == Settings.Modules.Ticket.Category.opti) {
+ event.replyEmbeds(new SimpleEmbedBuilder("Error")
+ .text("This ticket is already in the category for Opti.")
+ .error().build()).setEphemeral(true).queue();
+ return;
+ } else {
+ textChannel.getManager().setParent(event.getJDA().getCategoryById(Settings.Modules.Ticket.Category.opti)).queue();
+ event.replyEmbeds(new SimpleEmbedBuilder("Success")
+ .text("Successfully transferred the ticket to the category for Opti.")
+ .success().build()).setEphemeral(true).queue();
+ }
+ }
+ }
+ }
+ case "archive" -> {
+ }
+ case "unarchive" -> {
+ }
+ case "delete" -> {
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/verification/CheckAccountCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/verification/CheckAccountCommand.java
new file mode 100644
index 00000000..528395a2
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/verification/CheckAccountCommand.java
@@ -0,0 +1,34 @@
+package me.techscode.techdiscordbot.commands.verification;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import me.techscode.techdiscordbot.model.enums.Marketplace;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+import net.dv8tion.jda.api.interactions.commands.OptionType;
+import net.dv8tion.jda.api.interactions.commands.build.OptionData;
+
+
+public class CheckAccountCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the check-account command with its specific settings
+ */
+ public CheckAccountCommand() {
+ // Set the command
+ super("check-account");
+ // Set the description of the command
+ description("Check a marketplace ID for a verified user");
+ // Set to only the main guild
+ mainGuildOnly();
+ // Set the options that can be used
+ options(new OptionData(OptionType.STRING, "marketplace", "The marketplace where you want to check ", true)
+ .addChoice("Spigot", Marketplace.SPIGOT.getId())
+ .addChoice("MC-Market", Marketplace.BUILTBYBIT.getId())
+ .addChoice("Polymart", Marketplace.POLYMART.getId()),
+ new OptionData(OptionType.INTEGER, "ID", "The member ID of that marketplace", true));
+ }
+
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/commands/verification/CodeCommand.java b/src/main/java/me/TechsCode/TechDiscordBot/commands/verification/CodeCommand.java
new file mode 100644
index 00000000..0126666d
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/commands/verification/CodeCommand.java
@@ -0,0 +1,33 @@
+package me.techscode.techdiscordbot.commands.verification;
+
+import com.greazi.discordbotfoundation.handlers.commands.SimpleSlashCommand;
+import com.greazi.discordbotfoundation.utils.SimpleEmbedBuilder;
+import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
+
+import java.util.UUID;
+
+public class CodeCommand extends SimpleSlashCommand {
+
+ /**
+ * Create the timeout command with its specific settings
+ */
+ public CodeCommand() {
+ super("code");
+ description("Get a random code for verification");
+
+ mainGuildOnly();
+ }
+
+ @Override
+ protected void onCommand(final SlashCommandInteractionEvent event) {
+ final String code = UUID.randomUUID().toString().split("-")[0];
+
+ final SimpleEmbedBuilder builder = new SimpleEmbedBuilder("Manual Verification Code");
+ builder.text(
+ "Your custom verification code is:",
+ "```TechManualVerification." + code + "```"
+ );
+
+ event.replyEmbeds(builder.build()).queue();
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/Database.java b/src/main/java/me/TechsCode/TechDiscordBot/database/Database.java
new file mode 100644
index 00000000..d63b3142
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/Database.java
@@ -0,0 +1,22 @@
+package me.techscode.techdiscordbot.database;
+
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.database.tables.*;
+import org.jooq.DSLContext;
+
+// TODO: Check all debug and error messages from all the database files
+
+public class Database {
+
+ public static DSLContext sql = TechDiscordBot.getSqlManager().getDslContext();
+
+ public static MembersTable MEMBERSTable = new MembersTable();
+ public static Reminders REMINDERS = new Reminders();
+ public static Transcripts TRANSCRIPTS = new Transcripts();
+ public static Verifications VERIFICATIONS = new Verifications();
+ public static Purchases PURCHASES = new Purchases();
+ public static Tickets TICKETS = new Tickets();
+ public static ApplicationsTable APPLICATIONSTable = new ApplicationsTable();
+ public static PatreonTable PATREONTable = new PatreonTable();
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/TranscriptDatabase.java b/src/main/java/me/TechsCode/TechDiscordBot/database/TranscriptDatabase.java
new file mode 100644
index 00000000..829d1f56
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/TranscriptDatabase.java
@@ -0,0 +1,12 @@
+package me.techscode.techdiscordbot.database;
+
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.database.tables.Transcripts;
+import org.jooq.DSLContext;
+
+public class TranscriptDatabase {
+
+ public static DSLContext sql = TechDiscordBot.getTranscriptSqlManager().getDslContext();
+
+ public static Transcripts TRANSCRIPT = new Transcripts();
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/TranscriptSqlManager.java b/src/main/java/me/TechsCode/TechDiscordBot/database/TranscriptSqlManager.java
new file mode 100644
index 00000000..87652909
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/TranscriptSqlManager.java
@@ -0,0 +1,94 @@
+package me.techscode.techdiscordbot.database;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.debug.Debugger;
+import com.greazi.discordbotfoundation.settings.SimpleSettings;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import me.techscode.techdiscordbot.settings.Settings;
+import org.jooq.DSLContext;
+import org.jooq.SQLDialect;
+import org.jooq.impl.DSL;
+import org.jooq.meta.jaxb.Generator;
+import org.jooq.meta.jaxb.Jdbc;
+import org.jooq.meta.jaxb.Target;
+
+public class TranscriptSqlManager {
+
+ private static HikariDataSource dataSource;
+ private DSLContext dslContext = null;
+ private final String host = SimpleSettings.Database.Host();
+ private final String db = "TechDiscordBot";
+ private final String url = "jdbc:mysql://" + host + "/" + db;
+ private final String userName = Settings.Database.Transcript.username;
+ private final String password = Settings.Database.Transcript.password;
+
+ public TranscriptSqlManager() {
+ if (!SimpleSettings.Database.Enabled()) {
+ Common.log("MySQL system Disabled!");
+ return;
+ }
+ Common.log("Transcript Database system Enabled! Starting up Transcript MYSQL system");
+
+ final HikariConfig config = new HikariConfig();
+ config.setMinimumIdle(5);
+ config.setMaximumPoolSize(15);
+ config.setJdbcUrl(url);
+ config.setUsername(userName);
+ config.setPassword(password);
+
+ try {
+ dataSource = new HikariDataSource(config);
+ dslContext = DSL.using(dataSource, SQLDialect.MYSQL);
+ Common.log("Transcript MYSQL system Started!");
+ } catch (final Exception e) {
+ Debugger.printStackTrace(e);
+ }
+
+ if (!dataSource.isClosed()) {
+ Common.log("Successfully connected to Transcript MySQL database!");
+ } else {
+ Common.log("Failed to connect to Transcript MySQL database!");
+ }
+ }
+
+ public void codeGenerator() {
+ new org.jooq.meta.jaxb.Configuration()
+ .withJdbc(new Jdbc()
+ .withDriver("com.mysql.jdbc.Driver")
+ .withUrl(url)
+ .withUser(userName)
+ .withPassword(password)
+ )
+ .withGenerator(
+ new Generator()
+ .withDatabase(
+ new org.jooq.meta.jaxb.Database()
+ .withName(db)
+ .withIncludes(".*")
+ .withExcludes("" +
+ "UNUSED_TABLE # This table (unqualified name) should not be generated" +
+ "| PREFIX_.* # Objects with a given prefix should not be generated" +
+ "| SECRET_SCHEMA\\.SECRET_TABLE # This table (qualified name) should not be generated" +
+ "| SECRET_ROUTINE # This routine (unqualified name) ..." +
+ ""
+ )
+ .withInputSchema("[your database schema / owner / name]")
+ )
+ .withTarget(
+ new Target()
+ .withPackageName("com.greazi.discordbotfoundation.mysql")
+ .withDirectory("src/main/java/com/greazi/discordbotfoundation/mysql/generated")
+ )
+ );
+ }
+
+ public static HikariDataSource getDataSource() {
+ return dataSource;
+ }
+
+ public DSLContext getDslContext() {
+ return dslContext;
+ }
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlApplication.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlApplication.java
new file mode 100644
index 00000000..1f325691
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlApplication.java
@@ -0,0 +1,65 @@
+package me.techscode.techdiscordbot.database.entities;
+
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.model.enums.Application;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+
+import java.util.List;
+
+public class SqlApplication {
+
+ private int id;
+ private final int memberId;
+ private final long channelId;
+
+ private final long time;
+ private final String category;
+
+ public SqlApplication(final int memberId, final long channelId, final long time, final String category) {
+ this.memberId = memberId;
+ this.channelId = channelId;
+ this.time = time;
+ this.category = category;
+ }
+
+ public SqlApplication(final int id, final int memberId, final long channelId, final long time, final String category) {
+ this.id = id;
+ this.memberId = memberId;
+ this.channelId = channelId;
+ this.time = time;
+ this.category = category;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public List getMember() {
+ return Database.MEMBERSTable.getFromId(memberId);
+ }
+
+ public long getChannelId() {
+ return channelId;
+ }
+
+ public TextChannel getChannel() {
+ return TechDiscordBot.getMainGuild().getTextChannelById(channelId);
+ }
+
+ public Long getTime() {
+ return time;
+ }
+
+ public Application.Position getCategory() {
+ return Application.Position.getById(category);
+ }
+
+ public void save() {
+ Database.APPLICATIONSTable.add(this);
+ }
+
+ public void delete() {
+ Database.APPLICATIONSTable.remove(this.getChannelId());
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlMember.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlMember.java
new file mode 100644
index 00000000..1361bbbe
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlMember.java
@@ -0,0 +1,45 @@
+package me.techscode.techdiscordbot.database.entities;
+
+import com.greazi.discordbotfoundation.SimpleBot;
+import com.greazi.discordbotfoundation.settings.SimpleSettings;
+import me.techscode.techdiscordbot.database.Database;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+
+import java.util.Objects;
+
+public class SqlMember {
+
+ private int id;
+ private final long discordId;
+
+ public SqlMember(final long discordId) {
+ this.discordId = discordId;
+ }
+
+ public SqlMember(final int id, final long discordId) {
+ this.id = id;
+ this.discordId = discordId;
+ }
+
+ public int getId() {
+ return this.id;
+ }
+
+ public long getDiscordId() {
+ return this.discordId;
+ }
+
+ public Member getDiscordMember() {
+ return Objects.requireNonNull(SimpleBot.getJDA().getGuildById(SimpleSettings.Bot.MainGuild())).getMemberById(this.discordId);
+ }
+
+ public User getDiscordUser() {
+ return SimpleBot.getJDA().getUserById(this.discordId);
+ }
+
+ public void save() {
+ Database.MEMBERSTable.add(this);
+ }
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlPatreon.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlPatreon.java
new file mode 100644
index 00000000..84e2acdf
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlPatreon.java
@@ -0,0 +1,58 @@
+package me.techscode.techdiscordbot.database.entities;
+
+import me.techscode.techdiscordbot.database.Database;
+
+import javax.annotation.Nullable;
+import java.util.Optional;
+
+public class SqlPatreon {
+ private int id;
+ private final int memberId;
+ private final long join;
+ private long left;
+ private int tier;
+
+ public SqlPatreon(final int memberId, final long join) {
+ this.memberId = memberId;
+ this.join = join;
+ }
+
+
+ public SqlPatreon(final int id, final int memberId, final long join, final long left, int tier) {
+ this.id = id;
+ this.memberId = memberId;
+ this.join = join;
+ this.left = left;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ @Nullable
+ public SqlMember getSqlMember() {
+ final Optional SqlMember = Database.MEMBERSTable.getFromId(this.memberId).stream().findFirst();
+ return SqlMember.orElse(null);
+ }
+
+ public long getJoin() {
+ return join;
+ }
+
+ public long getLeft() {
+ return left;
+ }
+
+ public int getTier() {
+ return tier;
+ }
+
+ public boolean save() {
+ return Database.PATREONTable.add(this);
+ }
+
+ public boolean delete() {
+ return Database.PATREONTable.delete(this);
+ }
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlPreorder.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlPreorder.java
new file mode 100644
index 00000000..c59e94af
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlPreorder.java
@@ -0,0 +1,49 @@
+package me.techscode.techdiscordbot.database.entities;
+
+import java.sql.Timestamp;
+
+public class SqlPreorder {
+
+ private final String email;
+ private final long discordId;
+
+ private final String discordName;
+ private final String transactionId;
+ private final int patreon;
+
+ private final Timestamp lastDownload;
+
+ public SqlPreorder(final String email, final long discordId, final String discordName, final String transactionId, final int patreon, final Timestamp lastDownload) {
+ this.email = email;
+ this.discordId = discordId;
+ this.discordName = discordName;
+ this.transactionId = transactionId;
+ this.patreon = patreon;
+ this.lastDownload = lastDownload;
+ }
+
+ public String getEmail() {
+ return this.email;
+ }
+
+ public long getDiscordId() {
+ return this.discordId;
+ }
+
+ public String getDiscordName() {
+ return this.discordName;
+ }
+
+ public String getTransactionId() {
+ return this.transactionId;
+ }
+
+ public int getPatreon() {
+ return this.patreon;
+ }
+
+ public Timestamp getLastDownload() {
+ return this.lastDownload;
+ }
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlReminder.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlReminder.java
new file mode 100644
index 00000000..90a544b3
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlReminder.java
@@ -0,0 +1,75 @@
+package me.techscode.techdiscordbot.database.entities;
+
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.database.Database;
+import net.dv8tion.jda.api.entities.Member;
+
+import java.time.LocalDateTime;
+
+public class SqlReminder {
+
+ private int id;
+ private final int memberId;
+ private final long channelId;
+ private final long messageId;
+ private final LocalDateTime time;
+ private final int type;
+ private final String reminder;
+
+ public SqlReminder(final int memberId, final long channelId, final long messageId, final LocalDateTime time, final int type, final String reminder) {
+ this.memberId = memberId;
+ this.channelId = channelId;
+ this.messageId = messageId;
+ this.time = time;
+ this.type = type;
+ this.reminder = reminder;
+ }
+
+ public SqlReminder(final int id, final int memberId, final long channelId, final long messageId, final LocalDateTime time, final int type, final String reminder) {
+ this.id = id;
+ this.memberId = memberId;
+ this.channelId = channelId;
+ this.messageId = messageId;
+ this.time = time;
+ this.type = type;
+ this.reminder = reminder;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public Member getMember() {
+ for (final SqlMember member : Database.MEMBERSTable.getFromId(memberId)) {
+ if (TechDiscordBot.getJDA().getTextChannelById(channelId).getHistory().getMessageById(messageId).getAuthor().getIdLong() == member.getDiscordId()) {
+ return member.getDiscordMember();
+ }
+ }
+ return null;
+ }
+
+ public long getChannelId() {
+ return channelId;
+ }
+
+ public long getMessageId() {
+ return messageId;
+ }
+
+ public LocalDateTime getTime() {
+ return time;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public String getReminder() {
+ return reminder;
+ }
+
+ public void save() {
+ Database.REMINDERS.add(this);
+ }
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlTicket.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlTicket.java
new file mode 100644
index 00000000..88755fe2
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlTicket.java
@@ -0,0 +1,80 @@
+package me.techscode.techdiscordbot.database.entities;
+
+import me.techscode.techdiscordbot.TechDiscordBot;
+import me.techscode.techdiscordbot.database.Database;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+
+public class SqlTicket {
+
+ private int id;
+ private final long memberId;
+ private final long channelId;
+
+ private final long time;
+ private final String category;
+ private final String type;
+ private final String priority;
+
+ public SqlTicket(final long memberId, final long channelId, final long time, final String category, final String type, final String priority) {
+ this.memberId = memberId;
+ this.channelId = channelId;
+ this.time = time;
+ this.category = category;
+ this.type = type;
+ this.priority = priority;
+ }
+
+ public SqlTicket(final int id, final long memberId, final long channelId, final long time, final String category, final String type, final String priority) {
+ this.id = id;
+ this.memberId = memberId;
+ this.channelId = channelId;
+ this.time = time;
+ this.category = category;
+ this.type = type;
+ this.priority = priority;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public long getMemberId() {
+ return memberId;
+ }
+
+ public SqlMember getMember() {
+ return Database.MEMBERSTable.getFromId(Integer.parseInt(memberId + "")).get(0);
+ }
+
+ public long getChannelId() {
+ return channelId;
+ }
+
+ public TextChannel getChannel() {
+ return TechDiscordBot.getMainGuild().getTextChannelById(channelId);
+ }
+
+ public Long getTime() {
+ return time;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getPriority() {
+ return priority;
+ }
+
+ public void save() {
+ Database.TICKETS.add(this);
+ }
+
+ public void delete() {
+ Database.TICKETS.remove(this.getChannelId());
+ }
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlTranscript.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlTranscript.java
new file mode 100644
index 00000000..7860af5c
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/SqlTranscript.java
@@ -0,0 +1,28 @@
+package me.techscode.techdiscordbot.database.entities;
+
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.TranscriptDatabase;
+
+public class SqlTranscript {
+ private String id;
+ private final String value;
+
+ public SqlTranscript(final String id, final String value) {
+ this.id = id;
+ this.value = value;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getMessages() {
+ return value;
+ }
+
+ public void save() {
+ TranscriptDatabase.TRANSCRIPT.add(this);
+ }
+
+}
+
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/verification/SqlPurchase.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/verification/SqlPurchase.java
new file mode 100644
index 00000000..a2679f09
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/verification/SqlPurchase.java
@@ -0,0 +1,54 @@
+package me.techscode.techdiscordbot.database.entities.verification;
+
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.entities.SqlMember;
+
+import javax.annotation.Nullable;
+import java.util.Optional;
+
+public class SqlPurchase {
+ private int id;
+ private final int verificationId;
+ private final int pluginId;
+ private final String transactionId;
+
+ public SqlPurchase(final int verificationId, final int pluginId, final String transactionId) {
+ this.verificationId = verificationId;
+ this.pluginId = pluginId;
+ this.transactionId = transactionId;
+ }
+
+ public SqlPurchase(final int id, final int verificationId, final int pluginId, final String transactionId) {
+ this.id = id;
+ this.verificationId = verificationId;
+ this.pluginId = pluginId;
+ this.transactionId = transactionId;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public int getVerificationId() {
+ return verificationId;
+ }
+
+ @Nullable
+ public SqlMember getSqlMember() {
+ Optional sqlVerification = Database.VERIFICATIONS.getById(this.verificationId).stream().findFirst();
+ return sqlVerification.map(SqlVerification::getSqlMember).orElse(null);
+ }
+
+ public int getPluginId() {
+ return pluginId;
+ }
+
+ public String getTransactionId() {
+ return transactionId;
+ }
+
+ public void save() {
+ Database.PURCHASES.add(this);
+ }
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/entities/verification/SqlVerification.java b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/verification/SqlVerification.java
new file mode 100644
index 00000000..5002e06f
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/entities/verification/SqlVerification.java
@@ -0,0 +1,55 @@
+package me.techscode.techdiscordbot.database.entities.verification;
+
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.entities.SqlMember;
+import me.techscode.techdiscordbot.model.enums.Marketplace;
+
+import javax.annotation.Nullable;
+import java.util.Optional;
+
+public class SqlVerification {
+ private int id;
+ private final int memberId;
+ private final int marketplace;
+ private final int marketplaceUserId;
+
+ public SqlVerification(final int memberId, final Marketplace marketplace, final int marketplaceUserId) {
+ this.memberId = memberId;
+ this.marketplace = marketplace.getId();
+ this.marketplaceUserId = marketplaceUserId;
+ }
+
+ public SqlVerification(final int id, final int memberId, final int marketplace, final int marketplaceUserId) {
+ this.id = id;
+ this.memberId = memberId;
+ this.marketplace = marketplace;
+ this.marketplaceUserId = marketplaceUserId;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ @Nullable
+ public SqlMember getSqlMember() {
+ final Optional SqlMember = Database.MEMBERSTable.getFromId(this.memberId).stream().findFirst();
+ return SqlMember.orElse(null);
+ }
+
+ public int getMarketplace() {
+ return marketplace;
+ }
+
+ public int getMarketplaceUserId() {
+ return marketplaceUserId;
+ }
+
+ public boolean save() {
+ return Database.VERIFICATIONS.add(this);
+ }
+
+ public boolean delete() {
+ return Database.VERIFICATIONS.delete(this);
+ }
+
+}
diff --git a/src/main/java/me/TechsCode/TechDiscordBot/database/tables/ApplicationsTable.java b/src/main/java/me/TechsCode/TechDiscordBot/database/tables/ApplicationsTable.java
new file mode 100644
index 00000000..9497e016
--- /dev/null
+++ b/src/main/java/me/TechsCode/TechDiscordBot/database/tables/ApplicationsTable.java
@@ -0,0 +1,114 @@
+package me.techscode.techdiscordbot.database.tables;
+
+import com.greazi.discordbotfoundation.Common;
+import com.greazi.discordbotfoundation.debug.Debugger;
+import me.techscode.techdiscordbot.database.Database;
+import me.techscode.techdiscordbot.database.entities.SqlApplication;
+import me.techscode.techdiscordbot.model.enums.Application;
+import org.jooq.Query;
+import org.jooq.Select;
+import org.jooq.impl.DSL;
+
+import java.util.List;
+
+import static org.jooq.impl.DSL.field;
+import static org.jooq.impl.DSL.table;
+import static org.jooq.impl.SQLDataType.BIGINT;
+import static org.jooq.impl.SQLDataType.VARCHAR;
+
+public class ApplicationsTable {
+
+ public static final String TABLE_NAME = "applications";
+
+ public ApplicationsTable() {
+ createTable();
+ }
+
+ public void createTable() {
+ try {
+ Database.sql.createTableIfNotExists(TABLE_NAME)
+ .column("id", BIGINT.identity(true)).primaryKey("id")
+ .column("memberId", BIGINT)
+ .column("channelId", BIGINT)
+ .column("time", BIGINT)
+ .column("position", VARCHAR.nullable(true))
+ .constraint(
+ DSL.foreignKey("memberId").references(MembersTable.TABLE_NAME, "id")
+ )
+ .execute();
+ Debugger.debug("Database", "Created table " + TABLE_NAME);
+ } catch (final Exception e) {
+ Common.throwError(e, "Failed to create table " + TABLE_NAME);
+ }
+ }
+
+ public void add(final SqlApplication application) {
+ try {
+ Database.sql.insertInto(table(TABLE_NAME))
+ .set(field("memberId"), Database.MEMBERSTable.getFromDiscordId(application.getMember().get(0).getDiscordId()).get(0).getId())
+ .set(field("channelId"), application.getChannelId())
+ .set(field("time"), application.getTime())
+ .execute();
+ } catch (final Exception e) {
+ Common.throwError(e, "Failed to add a new application to the database",
+ "Member ID: " + application.getMember().get(0).getDiscordId(),
+ "Channel ID: " + application.getChannelId(),
+ "Time: " + application.getTime()
+ );
+ }
+ }
+
+ public void setPosition(final long channelId, final Application.Position position) {
+ try {
+ Database.sql.update(table(TABLE_NAME))
+ .set(field("position"), position.getId())
+ .where(field("channelId").eq(channelId))
+ .execute();
+ } catch (final Exception e) {
+ Common.throwError(e, "Failed to update application category in table " + TABLE_NAME);
+ }
+ }
+
+ public List get(final int id) {
+ try {
+ final Select> select = Database.sql.select().from(TABLE_NAME).where(field("id").eq(id));
+ return select.fetch().into(SqlApplication.class);
+ } catch (final Exception e) {
+ Common.throwError(e, "Failed to get application from table " + TABLE_NAME);
+ return null;
+ }
+ }
+
+ public List get(final long channelId) {
+ try {
+ final Select> select = Database.sql.select().from(TABLE_NAME).where(field("channelId").eq(channelId));
+ return select.fetch().into(SqlApplication.class);
+ } catch (final Exception e) {
+ Common.throwError(e, "Failed to get application from table " + TABLE_NAME);
+ return null;
+ }
+ }
+
+ public List