diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ba28af --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# Log file +*.log + +# IDE settings +.classpath +.project +.vscode +out/* +target/* +build/* + +# theia settings +.theia/ +**/.settings/org.eclipse.buildship.core.prefs + +# IntelliJ files +**/*.iml +**/.idea +**/.gradle +*.ipr +*.iws +**/out/ + +# gradle +**/build/ +!gradle/wrapper/*.jar + +# Ignore Mac DS_Store files +**/.DS_Store +/bin/ +config.json diff --git a/.settings/net.sf.jautodoc.prefs b/.settings/net.sf.jautodoc.prefs new file mode 100644 index 0000000..25bc25d --- /dev/null +++ b/.settings/net.sf.jautodoc.prefs @@ -0,0 +1,6 @@ +eclipse.preferences.version=1 +header_text=/*\r\n * The MIT License (MIT)\r\n *\r\n * Copyright (c) 2020 ROMVoid\r\n *\r\n * Permission is hereby granted, free of charge, to any person obtaining a copy of\r\n * this software and associated documentation files (the "Software"), to deal in\r\n * the Software without restriction, including without limitation the rights to\r\n * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r\n * the Software, and to permit persons to whom the Software is furnished to do so,\r\n * subject to the following conditions\:\r\n *\r\n * The above copyright notice and this permission notice shall be included in all\r\n * copies or substantial portions of the Software.\r\n *\r\n * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r\n * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r\n * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r\n * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r\n * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r\n */ +mode=mode_replace +project_specific_settings=true +replace_header=true +replacements=\n\n\nGets the\nSets the\nAdds the\nEdits the\nRemoves the\nInits the\nParses the\nCreates the\nBuilds the\nChecks if is\nPrints the\nChecks for\n\n\n diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..81c6189 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//src/main/java/net/romvoid/crashbot/utilities/HasteUtil.java=UTF-8 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f5c99a7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1 @@ +language: java \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e2086d5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 ROMVoid + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9abdd30 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +## Overview +CrashBot waits for users to upload files to discord and takes the file, and uploads said file to a hastebin style website so Moderators, helpers or anyone else can easily read the logs instead of having to download the logs every time one is posted. + +## Building + +### Prerequisite: +You will need the following to utilize all of features: +* JDK (8) +* Eclipse or Java supported IDE + +**We will not provide any support whatsoever in obtaining any of the above.** + +Please do note that you will not receive any help whatsoever while trying to build your own, your expected to know what your doing. + +1. Make sure you have the prerequisites installed and running (Make sure your Java version is up-to-date) +2. Clone this repository (you can also fork this repo and clone your fork). +3. Open a Terminal in the root folder. +4. Run `gradlew build` +5. Grab the jar from `build/libs` +6. Run the bot +7. On first run the terminal will ask for a bot-token (Again your excected to know how to obtain one) + + +## Release Notes +Can be found in [RELEASE_NOTES](RELEASE_NOTES.md). + +## Authors +* ROMVoid95 - [ROM](https://github.com/ROMVoid95) + +## Acknowledgments +* [JDA by DV8FromTheWorld and MinnDevelopment](https://github.com/DV8FromTheWorld/JDA) + + +## Contributing +Please, follow [Contributing](CONTRIBUTING.md) page. + +## Code of Conduct +Please, follow [Code of Conduct](CODE_OF_CONDUCT.md) page. + +## License +This project is licensed under **MIT** - see the [LICENSE](LICENSE) file for details diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md new file mode 100644 index 0000000..f031db8 --- /dev/null +++ b/RELEASE_NOTES.md @@ -0,0 +1,2 @@ +## 1.0.0 +* First Initial Release \ No newline at end of file diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..c419263 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..f2fc6ab --- /dev/null +++ b/build.gradle @@ -0,0 +1,91 @@ +plugins { + id 'application' + id 'java' + id "com.github.ben-manes.versions" version "0.28.0" + id "com.github.johnrengelman.shadow" version "5.2.0" + } + +mainClassName = 'net.romvoid.crashbot.Bot' +group = 'net.romvoid.crashbot' +version = '3.0.0' + +description = 'A Minecraft logs Discord Bot' + +configurations { + compile +} + +repositories { + maven { + url "https://jitpack.io" + } + jcenter() +} + +dependencies { + compile ('net.dv8tion:JDA:4.1.1_164'){ + transitive = true + exclude module: 'opus-java' + } + //compile group: '', name: '', version: '' + + compile group: 'com.jagrosh', name: 'jda-utilities', version: '3.0.4' + + // https://mvnrepository.com/artifact/commons-io/commons-io + compile group: 'commons-io', name: 'commons-io', version: '2.7' + + // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 + compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.11' + + // https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient + compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.12' + + // https://mvnrepository.com/artifact/com.google.code.gson/gson + compile group: 'com.google.code.gson', name: 'gson', version: '2.8.6' + + // https://mvnrepository.com/artifact/org.json/json + compile group: 'org.json', name: 'json', version: '20200518' + + // https://mvnrepository.com/artifact/org.slf4j/slf4j-api + compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.30' + + // https://mvnrepository.com/artifact/ch.qos.logback/logback-classic + compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.3' + + // https://bintray.com/minndevelopment/maven/discord-webhooks + compile group: 'club.minnced', name: 'discord-webhooks', version: '0.3.1' + + // https://search.maven.org/artifact/com.github.enerccio/gson-utilities/1.1.0/jar + compile group: 'com.github.enerccio', name: 'gson-utilities', version: '1.1.0' + + // https://mvnrepository.com/artifact/org.jsoup/jsoup + compile group: 'org.jsoup', name: 'jsoup', version: '1.13.1' + + // https://search.maven.org/artifact/org.junit.jupiter/junit-jupiter-engine + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.0-M1' + + compile(group: 'org.kohsuke', name: 'github-api', version: '1.95'){ + exclude module: 'okhttp' + } + + compile 'com.github.ROMVoid95:ReadOnlyCfg:1.0.2' + +} + +shadowJar { task -> + baseName = task.project.name +} + +jar { + + configurations.compile.each { dep -> + from(project.zipTree(dep)) { + exclude 'META-INF', 'META-INF/**' + } + } + manifest { + attributes( + 'Main-Class': mainClassName + ) + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..cc4fdc2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.jar Binary files differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..4e4abad --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..af6708f --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## 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"' + +# 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, switch paths to Windows format before running java +if $cygwin ; 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=$((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" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..6d57edc --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@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" + +@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/settings.gradle b/settings.gradle new file mode 100644 index 0000000..b6256e0 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'CrashBot' \ No newline at end of file diff --git a/solutions/solutions.json b/solutions/solutions.json new file mode 100644 index 0000000..7a096b4 --- /dev/null +++ b/solutions/solutions.json @@ -0,0 +1,22 @@ +[ + { + "keys": [ + "Galacticraft-Planets-Mod-1.12", + "MicdoodleCore-1.12" + ], + "reply": "You seem it have downloaded Galacticraft from an invalid site, please download from http://micdoodle8.com/mods/galacticraft/downloads" + }, + { + "keys": [ + "Galacticraft-Mod-1.12", + "MicdoodleCore-1.12" + ], + "reply": "You seem it have downloaded Galacticraft from an invalid site, please download from http://micdoodle8.com/mods/galacticraft/downloads" + }, + { + "keys": [ + "You have a double version of the same space station, station for planet ID: -31" + ], + "reply": "Disable the Venus Space Station in ExtraPlanets.cfg file or Galaxyspace/dimensions.cfg file." + } +] \ No newline at end of file diff --git a/src/main/java/net/romvoid/crashbot/Bot.java b/src/main/java/net/romvoid/crashbot/Bot.java new file mode 100644 index 0000000..9d42ec5 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/Bot.java @@ -0,0 +1,190 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 ROMVoid + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package net.romvoid.crashbot; + +import static net.dv8tion.jda.api.requests.GatewayIntent.*; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import javax.security.auth.login.LoginException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jagrosh.jdautilities.command.CommandClientBuilder; +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import com.jagrosh.jdautilities.examples.command.GuildlistCommand; + +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.OnlineStatus; +import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.requests.GatewayIntent; +import net.dv8tion.jda.api.utils.cache.CacheFlag; +import net.dv8tion.jda.internal.JDAImpl; +import net.romvoid.crashbot.commands.InviteCommand; +import net.romvoid.crashbot.config.Configuration; +import net.romvoid.crashbot.config.Setup; + +/** + * The Main Bot Class. + */ +public class Bot { + + private static Bot instance; + private JDAImpl jda; + private static final SimpleDateFormat timeStampFormatter = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss"); + /** The Constant CONFIG_KEYS. */ + private static final String[] CONFIG_KEYS = { "token", "prefix" }; + + /** The configuration. */ + private final Configuration configuration; + + private static EventWaiter waiter; + + public static CommandClientBuilder client; + + /** The prefix. */ + private static String prefix; + + private static Set intents = new HashSet<>(); + + public static final Logger LOG = LoggerFactory.getLogger(Bot.class); + + + /** + * Instantiates a new bot. + */ + private Bot() { + instance = this; + configuration = new Configuration(new File("config.json")); + for (String configKey : CONFIG_KEYS) { + if (!configuration.has(configKey)) { + String input = Setup.prompt(configKey); + configuration.set(configKey, input); + } + } + prefix = instance.configuration.getString("prefix"); + setIntents(); + client = new CommandClientBuilder(); + waiter = new EventWaiter(); + client.setOwnerId("626123188849475584"); + client.setEmojis("\uD83D\uDE03", "\uD83D\uDE2E", "\uD83D\uDE26"); + client.setPrefix(prefix); + + client.addCommands(new InviteCommand(), new GuildlistCommand(waiter)); + initJDA(); + + + } + + /** + * The main method. + * + * @param args the arguments + */ + public static void main(String[] args) { + if (instance != null) + throw new RuntimeException("CrashBot has already been initialized in this VM."); + new Bot(); + } + + /** + * Initiates the JDA Instance and builder. + */ + public static void initJDA() { + if (instance == null) + throw new NullPointerException("CrashBot has not been initialized yet."); + + try { + instance.jda = (JDAImpl) JDABuilder.create(instance.configuration.getString("token"), intents) + .setStatus(OnlineStatus.DO_NOT_DISTURB) + .setActivity(Activity.playing("Loading...").asRichPresence()) + .addEventListeners(waiter, client.build(), new MessageListener()) + .disableCache(CacheFlag.VOICE_STATE, CacheFlag.EMOTE).build(); + } catch (LoginException e) { + e.printStackTrace(); + } + getJDA().getPresence().setStatus(OnlineStatus.ONLINE); + getJDA().getPresence().setActivity(Activity.playing("MFND.ru")); + } + + private void setIntents() { + intents.add(GUILD_MESSAGES); + intents.add(GUILD_MEMBERS); + intents.add(GUILD_PRESENCES); + } + + /** + * Gets the single instance of Bot. + * + * @return single instance of Bot + */ + public static Bot getInstance() { + if (instance == null) + throw new IllegalStateException("Bot has not been initialised. Please use Bot#init() to create the bot"); + return instance; + } + + /** + * Gets the prefix. + * + * @return the prefix + */ + public String getPrefix() { + return prefix; + } + + /** + * Gets the configuration. + * + * @return the configuration + */ + public static Configuration getConfiguration() { + return instance == null ? null : instance.configuration; + } + + /** + * Gets the JDA Instance. + * + * @return the JDA Instance + */ + public static JDAImpl getJDA() { + return instance == null ? null : instance.jda; + } + + /** + * @return a freshly generated timestamp in the 'dd.MM.yyyy HH:mm:ss' format. + */ + public static String getNewTimestamp() { + return timeStampFormatter.format(new Date()); + } + + public static void logMsg(String messageId, String conent) { + String msg = "[" + messageId + "] " + conent; + Bot.LOG.info(msg); + } +} diff --git a/src/main/java/net/romvoid/crashbot/MessageListener.java b/src/main/java/net/romvoid/crashbot/MessageListener.java new file mode 100644 index 0000000..bb5dc9c --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/MessageListener.java @@ -0,0 +1,65 @@ +package net.romvoid.crashbot; + +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.romvoid.crashbot.file.FileHandler; +import net.romvoid.crashbot.file.Patterns; + +public class MessageListener extends ListenerAdapter { + + private String[] pasteSites = { "pastebin.com", "paste.ubuntu.com", "pastebin.ubuntu.com", "ghostbin.co", + "paste.ee", "paste.dimdev.org" }; + private String[] special = { "pastebin.ubuntu.com", "paste.ubuntu.com" }; + private String url; + private boolean foundUrl; + private Matcher matcher; + private boolean isPasteURL; + private boolean isUbuntuURL; + private Matcher urlSplit; + + @Override + public void onMessageReceived(MessageReceivedEvent event) { + if(event.getAuthor().isBot()) {return;} + if (!event.getMessage().getAttachments().isEmpty()) { + new FileHandler(event); + return; + } + if (event.getMessage().getAttachments().isEmpty()) { + matcher = Patterns.Url.PASTEURL.matcher(event.getMessage().getContentStripped()); + foundUrl = matcher.find(); + System.out.println("Found URL: " + foundUrl); + if (foundUrl) { + url = matcher.group(0); + isPasteURL = isPasteSite(url); + System.out.println("is PasteSite: " + isPasteURL); + if (isPasteURL) { + Pattern pattern = Pattern.compile(Patterns.Url.DIVIDEURL); + urlSplit = pattern.matcher(url); + if (urlSplit.find()) + isUbuntuURL = isSpecialPasteSite(urlSplit.group(1)); + System.out.println("is UbuntuPaste: " + isUbuntuURL); + if (isUbuntuURL) { + new FileHandler(event, url); + return; + } else { + new FileHandler(event, urlSplit.group(1), urlSplit.group(2)); + return; + } + } + } + } + } + + private boolean isSpecialPasteSite(String message) { + return Arrays.stream(special).parallel().anyMatch(message::contains); + } + + private boolean isPasteSite(String message) { + return Arrays.stream(pasteSites).parallel().anyMatch(message::contains); + } + +} diff --git a/src/main/java/net/romvoid/crashbot/commands/Cmd.java b/src/main/java/net/romvoid/crashbot/commands/Cmd.java new file mode 100644 index 0000000..b4a2de3 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/commands/Cmd.java @@ -0,0 +1,16 @@ +package net.romvoid.crashbot.commands; + +import com.jagrosh.jdautilities.command.Command; +import com.jagrosh.jdautilities.command.CommandEvent; + +import net.romvoid.crashbot.Bot; + +public abstract class Cmd extends Command { + + protected abstract void execute(CommandEvent event); + + void log(CommandEvent event) { + Bot.LOG.info(event.getAuthor().getName() + " invoked command " + this.name); + } + +} diff --git a/src/main/java/net/romvoid/crashbot/commands/GuildsCommand.java b/src/main/java/net/romvoid/crashbot/commands/GuildsCommand.java new file mode 100644 index 0000000..1895796 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/commands/GuildsCommand.java @@ -0,0 +1,67 @@ +package net.romvoid.crashbot.commands; + +import java.awt.Color; +import java.util.concurrent.TimeUnit; + +import com.jagrosh.jdautilities.command.Command; +import com.jagrosh.jdautilities.command.CommandEvent; +import com.jagrosh.jdautilities.commons.waiter.EventWaiter; +import com.jagrosh.jdautilities.doc.standard.CommandInfo; +import com.jagrosh.jdautilities.doc.standard.Error; +import com.jagrosh.jdautilities.menu.Paginator; + +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.exceptions.PermissionException; +import net.romvoid.crashbot.Bot; + +@CommandInfo(name = "guilds", description = "Gets a paginated list of the guilds the bot is on.", requirements = { + "The bot has all necessary permissions.", "The user is the bot's owner." }) +@Error(value = "If arguments are provided, but they are not an integer.", response = "[PageNumber] is not a valid integer!") +public class GuildsCommand extends Command { + + private final Paginator.Builder pbuilder; + + public GuildsCommand(EventWaiter waiter) { + this.name = "guilds"; + this.help = "shows the list of guilds the bot is on"; + this.arguments = "[pagenum]"; + this.guildOnly = false; + this.ownerCommand = true; + pbuilder = new Paginator.Builder().setColumns(1).setItemsPerPage(10).showPageNumbers(true) + .waitOnSinglePage(false).useNumberedItems(false).setFinalAction(m -> { + try { + m.clearReactions().queue(); + } catch (PermissionException ex) { + m.delete().queue(); + } + }).setEventWaiter(waiter).setTimeout(1, TimeUnit.MINUTES); + } + + @Override + protected void execute(CommandEvent event) { + Bot.LOG.info(event.getAuthor().getName() + " invoked command " + this.name); + int page = 1; + if (!event.getArgs().isEmpty()) { + try { + page = Integer.parseInt(event.getArgs()); + } catch (NumberFormatException e) { + event.reply(event.getClient().getError() + " `" + event.getArgs() + "` is not a valid integer!"); + return; + } + } + pbuilder.clearItems(); + event.getJDA().getGuilds().stream() + .map(g -> "**" + g.getName() + "** (ID:" + g.getId() + ") ~ " + g.getMembers().size() + " Members") + .forEach(pbuilder::addItems); + Paginator p = pbuilder + .setColor(event.isFromType(ChannelType.TEXT) ? event.getSelfMember().getColor() : Color.black) + .setText(event.getClient().getSuccess() + " Guilds that **" + event.getSelfUser().getName() + + "** is connected to" + + (event.getJDA().getShardInfo() == null ? ":" + : "(Shard ID " + event.getJDA().getShardInfo().getShardId() + "):")) + .setUsers(event.getAuthor()).build(); + p.paginate(event.getChannel(), page); + event.getMessage().delete().queue(); + } + +} diff --git a/src/main/java/net/romvoid/crashbot/commands/InviteCommand.java b/src/main/java/net/romvoid/crashbot/commands/InviteCommand.java new file mode 100644 index 0000000..34763ee --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/commands/InviteCommand.java @@ -0,0 +1,50 @@ +package net.romvoid.crashbot.commands; + +import java.util.concurrent.TimeUnit; + +import com.jagrosh.jdautilities.command.Command; +import com.jagrosh.jdautilities.command.CommandEvent; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.romvoid.crashbot.Bot; +import net.romvoid.crashbot.utilities.EmbedUtil; + +public class InviteCommand extends Command { + + public InviteCommand() { + this.name = "invite"; + this.help = "Generates an invite link for the bot"; + this.guildOnly = false; + } + + @Override + protected void execute(CommandEvent event) { + Bot.LOG.info(event.getAuthor().getName() + " invoked command " + this.name); + MessageChannel channel = event.getChannel(); + String inviteURL = Bot.getJDA().getInviteUrl() + "&permissions=388177"; + if (event.getArgs().isEmpty()) { + EmbedBuilder embed = EmbedUtil.embed("Invite Me To Your Server", + "Want to use this bot in your server also? No problem! heres your invite link"); + embed.addField("Invite Link", "[Invite Me](" + inviteURL + ")", false); + Message msg = EmbedUtil.message(embed); + EmbedUtil.sendAndDeleteOnGuilds(channel, msg, 2, TimeUnit.MINUTES); + } else { + String[] args = event.getArgs().split("\\s+"); + if (args.length >= 2) { + event.replyWarning("You can only define 1 serverId per command!"); + } else { + String specialInvite = inviteURL + "&guild_id=" + args[0]; + EmbedBuilder embed = EmbedUtil.embed("Invite Me To Your Server", + "Want to use this bot in your server also? No problem! heres your invite link"); + embed.addField("Here is your direct link to invite the bot", "[Invite Me](" + specialInvite + ")", + false); + Message msg = EmbedUtil.message(embed); + EmbedUtil.sendAndDeleteOnGuilds(channel, msg, 2, TimeUnit.MINUTES); + } + } + event.getMessage().delete().queue(); + } + +} diff --git a/src/main/java/net/romvoid/crashbot/config/Configuration.java b/src/main/java/net/romvoid/crashbot/config/Configuration.java new file mode 100644 index 0000000..6b28491 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/config/Configuration.java @@ -0,0 +1,189 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 ROMVoid + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package net.romvoid.crashbot.config; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class Configuration { + + private File file; + private JsonObject json; + public JsonParser jsonParser; + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + public Configuration(final File file) { + + this.file = file; + String cont = null; + + try { + if (file.exists()) { + BufferedReader reader = new BufferedReader(new FileReader(file)); + cont = reader.lines().collect(Collectors.joining("\n")); + reader.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + if (cont == null || cont.equals("")) { + cont = "{}"; + } + json = JsonParser.parseString(cont).getAsJsonObject(); + + } + + /** + * @param key + * @param val + * @description Sets tha value of a key in config + */ + public Configuration set(final String key, final String val) { + if (json.has(key)) { + json.remove(key); + } + if (val != null) { + json.addProperty(key, val); + } + return this.save(); + } + + /** + * @param key + * @param val + * @description Sets the value of a key in config + */ + public Configuration set(final String key, final int val) { + if (json.has(key)) { + json.remove(key); + } + this.json.addProperty(key, val); + return this.save(); + } + + /** + * @param key + * @description Removes key from config + */ + public Configuration unset(final String key) { + if (json.has(key)) + json.remove(key); + + return this.save(); + } + + /** + * @description Saves the config + */ + private Configuration save() { + try { + if (json.entrySet().size() == 0) { + if (file.exists()) { + file.delete(); + } + } else { + if (!file.exists()) { + file.createNewFile(); + } + + BufferedWriter br = new BufferedWriter(new FileWriter(file)); + String jsonOut = gson.toJson(json); + br.write(jsonOut); + br.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return this; + } + + /** + * @param key + * @return Value of key in config as string + */ + public String getString(final String key) { + try { + return json.get(key).getAsString(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + /** + * @param key + * @return Value of key in config as integer + */ + public int getInt(final String key) { + if (json.has(key)) { + return json.get(key).getAsInt(); + } + return 0; + } + + /** + * @param key + * @return If key exists + */ + public boolean has(final String key) { + try { + return json.has(key); + } catch (NullPointerException ex) { + return false; + } + } + + public List keySet() { + List keys = new ArrayList<>(); + Set> entries = json.entrySet(); + for (Map.Entry entry : entries) { + keys.add(entry.getKey()); + } + return keys; + } + + public List values() { + List values = new ArrayList<>(); + Set> entries = json.entrySet(); + for (Map.Entry entry : entries) { + values.add(entry.getValue().getAsString()); + } + return values; + } + + +} \ No newline at end of file diff --git a/src/main/java/net/romvoid/crashbot/config/InteralConfig.java b/src/main/java/net/romvoid/crashbot/config/InteralConfig.java new file mode 100644 index 0000000..12a1498 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/config/InteralConfig.java @@ -0,0 +1,13 @@ +package net.romvoid.crashbot.config; + +public class InteralConfig { + + public String webhookUrl; + + public InteralConfig() {} + + public String getWebhookUrl() { + return this.webhookUrl; + } + +} diff --git a/src/main/java/net/romvoid/crashbot/config/Setup.java b/src/main/java/net/romvoid/crashbot/config/Setup.java new file mode 100644 index 0000000..729e1e9 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/config/Setup.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 ROMVoid + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package net.romvoid.crashbot.config; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class Setup { + + private static final BufferedReader sys_in; + + static { + InputStreamReader isr = new InputStreamReader(System.in); + sys_in = new BufferedReader(isr); + } + + public static String prompt(String req) { + String token; + + // prompt for token + System.out.println("Enter The Bots " + req + ":"); + + + try { + // read and trim line + String line = sys_in.readLine(); + token = line.trim(); + + return token; + } catch (IOException e) { + System.err.println(e.getMessage()); + } + // RAGEQUIT + System.out.println("Exiting"); + Runtime.getRuntime().exit(1); + return null; + } +} diff --git a/src/main/java/net/romvoid/crashbot/config/StringUtil.java b/src/main/java/net/romvoid/crashbot/config/StringUtil.java new file mode 100644 index 0000000..78a213b --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/config/StringUtil.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 ROMVoid + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package net.romvoid.crashbot.config; + +public class StringUtil { + /** + * Check if String is numeric. + * + * @param str the String which should be tested. + * @return true if String is Numeric else false. + */ + @SuppressWarnings("unused") + public static boolean isNumeric(String str) { + try { + double d = Double.parseDouble(str); + } catch (NumberFormatException nfe) { + return false; + } + return true; + } + + /** + * Create Emoji out of Code points + * + * @param str the Code point. + * @return the Emoji as a String. + */ + public static String emojiOutCodePoint(String str) { + int[] codepoints = {Integer.valueOf(str.replace("U+", "0x"))}; + String s = new String(codepoints, 0, codepoints.length); + return s; + } + + public static boolean nicknameHasBrackets(String nickname) { + if (nickname.contains("[") || nickname.contains("]")) { + return true; + } + return false; + + } +} diff --git a/src/main/java/net/romvoid/crashbot/file/Embeds.java b/src/main/java/net/romvoid/crashbot/file/Embeds.java new file mode 100644 index 0000000..8a11e9f --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/file/Embeds.java @@ -0,0 +1,153 @@ +package net.romvoid.crashbot.file; + +import java.awt.Color; +import java.net.URI; +import java.time.Instant; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; + +public class Embeds { + + private static final String SOLUTION_FOOTER = "Solutions are provided on a best-attempt basis and are not guaranteed"; + + /** + * Make crashlogWithSolutionEmbed. + * + * @param channel the channel + * @param message the message + * @param filename the filename + * @param url the URL + * @param fix the fix + * @return the embed builder + */ + public static EmbedBuilder crashlogWithSolutionEmbed(TextChannel channel, Message message, String filename, URI url, String fix) { + String user = message.getAuthor().getName() + "#" + message.getAuthor().getDiscriminator(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.GREEN); + embedBuilder.setTitle("Crash Report Utility"); + embedBuilder.setDescription("`Links do not expire`"); + embedBuilder.addField(user + "'s Crash Log", "[" + filename + "](" + url + ")", false); + embedBuilder.addField("Possible Fixes", "`" + fix + "`", false); + embedBuilder.setFooter(SOLUTION_FOOTER + "\nCrash-Log Service for " + channel.getGuild().getName()); + embedBuilder.setTimestamp(Instant.now()); + return embedBuilder; + } + + /** + * Make crashlogOnlyEmbed. + * + * @param channel the channel + * @param message the message + * @param filename the filename + * @param url the URL + * @param fix the fix + * @return the embed builder + */ + public static EmbedBuilder crashlogOnlyEmbed(TextChannel channel, Message message, String filename, URI url) { + String user = message.getAuthor().getName() + "#" + message.getAuthor().getDiscriminator(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.cyan); + embedBuilder.setTitle("Crash Report Utility"); + embedBuilder.setDescription("`Links do not expire`"); + embedBuilder.addField(user + "'s Crash Log", "[" + filename + "](" + url + ")", false); + embedBuilder.setFooter("Crash-Log Service for " + channel.getGuild().getName()); + embedBuilder.setTimestamp(Instant.now()); + return embedBuilder; + } + + /** + * Make crashlogNotSupportedEmbed. + * + * @param channel the channel + * @param message the message + * @param filename the filename + * @param url the URL + * @param version the version + * @return the embed builder + */ + public static EmbedBuilder crashlogNotSupportedEmbed(TextChannel channel, Message message, String filename, URI url, String version) { + String user = message.getAuthor().getName() + "#" + message.getAuthor().getDiscriminator(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle("Crash Report Utility"); + embedBuilder.setDescription("`Links do not expire`"); + embedBuilder.addField(user + "'s Crash Log", "[" + filename + "](" + url + ")", false); + embedBuilder.addField("Version Not Supported","`" + version + "` is no longer supported." + + "\nYour URL is still provided in the case any community members may know a fix", false); + embedBuilder.setFooter(channel.getGuild().getName()); + embedBuilder.setTimestamp(Instant.now()); + return embedBuilder; + } + + /** + * Make crashlogWithSolutionEmbed. + * + * @param channel the channel + * @param message the message + * @param filename the filename + * @param url the URL + * @param fix the fix + * @return the embed builder + */ + public static EmbedBuilder crashlogWithSolutionEmbed(TextChannel channel, Message message, String url, String fix) { + String user = message.getAuthor().getName() + "#" + message.getAuthor().getDiscriminator(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.GREEN); + embedBuilder.setTitle("Crash Report Utility"); + embedBuilder.setDescription("`Links do not expire`"); + embedBuilder.addField(user + "'s Crash Log", "[" + url + "](" + url + ")", false); + embedBuilder.addField("Possible Fixes", "`" + fix + "`", false); + embedBuilder.setFooter(SOLUTION_FOOTER + "\nCrash-Log Service for " + channel.getGuild().getName()); + embedBuilder.setTimestamp(Instant.now()); + return embedBuilder; + } + + /** + * Make crashlogOnlyEmbed. + * + * @param channel the channel + * @param message the message + * @param filename the filename + * @param url the URL + * @param fix the fix + * @return the embed builder + */ + public static EmbedBuilder crashlogOnlyEmbed(TextChannel channel, Message message, String url) { + String user = message.getAuthor().getName() + "#" + message.getAuthor().getDiscriminator(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.cyan); + embedBuilder.setTitle("Crash Report Utility"); + embedBuilder.setDescription("`Links do not expire`"); + embedBuilder.addField(user + "'s Crash Log", "[" + url + "](" + url + ")", false); + embedBuilder.setFooter("Crash-Log Service for " + channel.getGuild().getName()); + embedBuilder.setTimestamp(Instant.now()); + return embedBuilder; + } + + /** + * Make crashlogNotSupportedEmbed. + * + * @param channel the channel + * @param message the message + * @param filename the filename + * @param url the URL + * @param version the version + * @return the embed builder + */ + public static EmbedBuilder crashlogNotSupportedEmbed(TextChannel channel, Message message, String url, String version) { + String user = message.getAuthor().getName() + "#" + message.getAuthor().getDiscriminator(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.RED); + embedBuilder.setTitle("Crash Report Utility"); + embedBuilder.setDescription("`Links do not expire`"); + embedBuilder.addField(user + "'s Crash Log", "[" + url + "](" + url + ")", false); + embedBuilder.addField("Version Not Supported","`" + version + "` is no longer supported." + + "\nYour URL is still provided in the case any community members may know a fix", false); + embedBuilder.setFooter(channel.getGuild().getName()); + embedBuilder.setTimestamp(Instant.now()); + return embedBuilder; + } + +} diff --git a/src/main/java/net/romvoid/crashbot/file/FileHandler.java b/src/main/java/net/romvoid/crashbot/file/FileHandler.java new file mode 100644 index 0000000..d9c4ac9 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/file/FileHandler.java @@ -0,0 +1,227 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 ROMVoid + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package net.romvoid.crashbot.file; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.Message.Attachment; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.romvoid.crashbot.Bot; +import net.romvoid.crashbot.file.solution.FileUtil; +import net.romvoid.crashbot.file.solution.Parser; +import net.romvoid.crashbot.file.solution.Solution; +import net.romvoid.crashbot.utilities.HasteUtil; + +/** + * The listener interface for receiving file events. The class that is + * interested in processing a file event implements this interface, and the + * object created with that class is registered with a component using the + * component's addFileListener method. When the file event occurs, + * that object's appropriate method is invoked. + * + * @see FileEvent + */ +public class FileHandler { + private static StringBuilder builder = new StringBuilder(); + static final Map cache = new HashMap<>(); + private MessageReceivedEvent event; + List list; + private String messageId; + private TextChannel channel; + private Message message; + private String name; + private String author; + + public FileHandler(MessageReceivedEvent event) { + this.event = event; + + this.list = new ArrayList(event.getMessage().getAttachments()); + this.message = event.getMessage(); + this.channel = event.getTextChannel(); + this.messageId = event.getMessageId(); + this.author = event.getAuthor().getAsTag(); + + this.handleFile(); + } + + public FileHandler(MessageReceivedEvent event, String url) { + this.event = event; + this.message = event.getMessage(); + this.channel = event.getTextChannel(); + this.messageId = event.getMessageId(); + this.author = event.getAuthor().getAsTag(); + + this.getContentFromUbuntu(url, this.messageId); + } + + public FileHandler(MessageReceivedEvent event, String url, String id) { + this.event = event; + this.message = event.getMessage(); + this.channel = event.getTextChannel(); + this.messageId = event.getMessageId(); + this.author = event.getAuthor().getAsTag(); + + this.getContent(url, id , this.messageId); + } + + /** + * On message received. + * + * @param event the onMessageReceived event + */ + private void handleFile() { + + list.forEach(file -> { + this.name = file.getFileName(); + switch (file.getFileExtension()) { + case "txt": + if (FileUtil.matchToExt(Patterns.Filenames.CRASHLOG, file.getFileName())) { + Bot.logMsg(messageId, author + " submitted " + name); + getFileContent(file, messageId); + } + break; + case "log": + if (FileUtil.matchToExt(Patterns.Filenames.LOGS_TXT, file.getFileName())) { + Bot.logMsg(messageId, author + " submitted " + name); + getFileContent(file, messageId); + } + break; + } + }); + + } + + public static void sendEmbed(TextChannel channel, EmbedBuilder embed) { + channel.sendMessage(embed.build()).queue(); + } +// +// public static void sendPing(TextChannel channel, String asMention) { +// channel.sendMessage(asMention).queue(); +// } + + /** + * Gets the content of the log for processing to upload to hastebin + * + * @param event the onMessageReceived event + * @return the file content + */ + private void getFileContent(Attachment doc, String messageId) { + doc.retrieveInputStream().thenAccept(in -> { + builder = new StringBuilder(); + byte[] buf = new byte[1024]; + int count = 0; + try { + while ((count = in.read(buf)) > 0) { + builder.append(new String(buf, 0, count)); + } + } catch (IOException e) { + e.printStackTrace(); + } + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + String msg = builder.toString(); + HasteUtil.paste(msg); + Solution foundSolution = Parser.find(msg); + boolean unsupported = Parser.checkVersion(msg); + System.out.println("Supported: " + unsupported); + EmbedBuilder embed; + + if(!unsupported) { + embed = Embeds.crashlogNotSupportedEmbed(channel, message, name, HasteUtil.getLink(), Parser.version); + sendEmbed(channel, embed); + } else { + if(foundSolution != null) { + embed = Embeds.crashlogWithSolutionEmbed(channel, message, name, HasteUtil.getLink(), foundSolution.getReply()); + sendEmbed(channel, embed); + } else { + embed = Embeds.crashlogOnlyEmbed(channel, message, name, HasteUtil.getLink()); + sendEmbed(channel, embed); + } + } + this.event.getMessage().delete().queue(); + }).exceptionally(t -> { // handle failure + t.printStackTrace(); + return null; + }); + } + + private void getContent(String url, String id, String messageId) { + String URLString = url + "raw/" + id + "/"; + String msg = HasteUtil.getOtherPaste(URLString); + HasteUtil.paste(msg); + Solution foundSolution = Parser.find(msg); + boolean unsupported = Parser.checkVersion(msg); + System.out.println("Supported: " + unsupported); + EmbedBuilder embed; + String name = HasteUtil.getLink().toString(); + + if(!unsupported) { + embed = Embeds.crashlogNotSupportedEmbed(channel, message, name, Parser.version); + sendEmbed(channel, embed); + } else { + if(foundSolution != null) { + embed = Embeds.crashlogWithSolutionEmbed(channel, message, name, foundSolution.getReply()); + sendEmbed(channel, embed); + } else { + embed = Embeds.crashlogOnlyEmbed(channel, message, name); + sendEmbed(channel, embed); + } + } + this.event.getMessage().delete().queue(); + } + + private void getContentFromUbuntu(String url, String messageId) { + String msg = HasteUtil.getCrashFromUbuntuPaste(url); + HasteUtil.paste(msg); + Solution foundSolution = Parser.find(msg); + boolean unsupported = Parser.checkVersion(msg); + System.out.println("Supported: " + unsupported); + EmbedBuilder embed; + + String name = HasteUtil.getLink().toString(); + + if(!unsupported) { + embed = Embeds.crashlogNotSupportedEmbed(channel, message, name, Parser.version); + sendEmbed(channel, embed); + } else { + if(foundSolution != null) { + embed = Embeds.crashlogWithSolutionEmbed(channel, message, name, foundSolution.getReply()); + sendEmbed(channel, embed); + } else { + embed = Embeds.crashlogOnlyEmbed(channel, message, name); + sendEmbed(channel, embed); + } + } + this.event.getMessage().delete().queue(); + } +} diff --git a/src/main/java/net/romvoid/crashbot/file/Patterns.java b/src/main/java/net/romvoid/crashbot/file/Patterns.java new file mode 100644 index 0000000..7dc4ad5 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/file/Patterns.java @@ -0,0 +1,38 @@ +package net.romvoid.crashbot.file; + +import java.util.regex.Pattern; + +public final class Patterns { + + public static final class Filenames { + private final static String DATE = "(19|20)[0-9]{2}[- \\/.](0[1-9]|1[012])[- \\/.](0[1-9]|[12][0-9]|3[01])"; + private final static String TIME = "(?:[01]\\d|2[0123]).(?:[012345]\\d).(?:[012345]\\d)"; + + public static final Pattern CRASHLOG = Pattern + .compile("(crash-" + DATE + "_" + TIME + "-(client|server).(txt)|(message).(txt))"); + public static final Pattern LOGS_TXT = Pattern.compile("(latest|message).(txt|log)"); + public static final Pattern LOG_GZ = Pattern + .compile("([12]\\d{3})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])-([1-9]).(log.gz)"); + public static final Pattern ARCHIVE = Pattern.compile("(tar|gz|zip|7z|rar)"); + + public final static Pattern DISCORD_MSG_URL = Pattern + .compile("(https:\\/\\/cdn.discordapp.com\\/attachments\\/)(\\d{17,20})\\/(\\d{17,20})\\/"); + } + + public static final class Url { + public static final Pattern PASTEURL = Pattern.compile("https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)"); + public static final String DIVIDEURL = "((?:https?:\\/\\/)?\\.?(?:[-;:&=\\+\\$,\\w]+@)?[A-Za-z0-9.-]+|(?:www.)[A-Za-z0-9.-]+)((?:\\/[\\+~%\\/.\\w-_]*)?\\??(?:[-\\+=&;%@.\\w_]*)#?(?:[.\\!\\/\\\\w]*))?"; + } + + public static final class Discord { + public final static Pattern DISCORD_ID = Pattern.compile("\\d{17,20}"); // ID + public final static Pattern FULL_USER_REF = Pattern.compile("(\\S.{0,30}\\S)\\s*#(\\d{4})"); // $1 -> username, + // $2 + // -> + // discriminator + public final static Pattern USER_MENTION = Pattern.compile("<@!?(\\d{17,20})>"); // $1 -> ID + public final static Pattern CHANNEL_MENTION = Pattern.compile("<#(\\d{17,20})>"); // $1 -> ID + public final static Pattern ROLE_MENTION = Pattern.compile("<@&(\\d{17,20})>"); // $1 -> ID + public final static Pattern EMOTE_MENTION = Pattern.compile("<:(.{2,32}):(\\d{17,20})>"); + } +} diff --git a/src/main/java/net/romvoid/crashbot/file/solution/FileUtil.java b/src/main/java/net/romvoid/crashbot/file/solution/FileUtil.java new file mode 100644 index 0000000..14ab34f --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/file/solution/FileUtil.java @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 ROMVoid + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package net.romvoid.crashbot.file.solution; + +import java.io.File; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.FilenameUtils; + +public class FileUtil { + + public static boolean matchToExt(Pattern pattern, String filename) { + Matcher matcher = pattern.matcher(filename); + return matcher.matches(); + } + + public static String getFileExtension(String filename) { + return FilenameUtils.getExtension(filename); + } + + public static boolean isArchive(File file) { + return Pattern.matches("log.gz", getFileExtension(file.getName())); + } + +} diff --git a/src/main/java/net/romvoid/crashbot/file/solution/Parser.java b/src/main/java/net/romvoid/crashbot/file/solution/Parser.java new file mode 100644 index 0000000..d56a1e3 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/file/solution/Parser.java @@ -0,0 +1,67 @@ +package net.romvoid.crashbot.file.solution; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.util.Arrays; + +import org.apache.commons.io.IOUtils; + +public class Parser { + + private static String[] notSupported = new String[] { "Minecraft Version: 1.8.9" }; + public static String version; + + public static boolean checkVersion(String message) { + boolean result = true; + try { + BufferedReader reader = new BufferedReader( + new InputStreamReader(IOUtils.toInputStream(message, Charset.defaultCharset()))); + String line = null; + int currentLine = 0; + while ((line = reader.readLine()) != null) { + currentLine++; + for (String ver : notSupported) { + if (line.contains(ver)) { + version = ver.replace("Minecraft Version: ", ""); + System.out.println(version); + return false; + } + } + } + reader.close(); + } catch (IOException e) { + + } + return result; + } + + public static Solution find(String message) { +// ArrayList result = new ArrayList<>(); +// InputStreamReader isr = new InputStreamReader(IOUtils.toInputStream(message, Charset.defaultCharset())); +// try(BufferedReader br = new BufferedReader(isr)) { +// while (br.ready()) { +// result.add(br.readLine()); +// } +// } catch (IOException e) { +// e.printStackTrace(); +// } + for (Solution solution : SolutionFile.getSolutions()) { + if(Arrays.stream(solution.getKeys().toArray(new String[0])).parallel().allMatch(message::contains)) { + return solution; + } +// int arraySize = result.size(); +// for (int i = 0; i < arraySize; i ++) { +// for(String key : solution.getKeys()) { +// if(result.get(i).contains(key)) { +// System.out.println("Line #" + i + " matches Key: " + key); +// return solution; +// } +// } +// } + } + return null; + } + +} diff --git a/src/main/java/net/romvoid/crashbot/file/solution/Solution.java b/src/main/java/net/romvoid/crashbot/file/solution/Solution.java new file mode 100644 index 0000000..c329dd4 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/file/solution/Solution.java @@ -0,0 +1,64 @@ +package net.romvoid.crashbot.file.solution; + +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Solution { + + @SerializedName("keys") + @Expose + public List keys; + @SerializedName("reply") + @Expose + public String reply; + + public Solution() {} + + /** + * + * @param keys + * @param reply + */ + public Solution(String reply, String... keys) { + super(); + this.keys = Arrays.asList(keys); + this.reply = reply; + } + + public List getKeys() { + return keys; + } + + public void setKeys(String... keys) { + this.keys = Arrays.asList(keys);; + } + + public Solution withKeys(String... keys) { + this.keys = Arrays.asList(keys);; + return this; + } + + public String getReply() { + return reply; + } + + public void setReply(String reply) { + this.reply = reply; + } + + public Solution withReply(String reply) { + this.reply = reply; + return this; + } + + @Override + public String toString() { + return new ToStringBuilder(this).append("keys", keys).append("reply", reply).toString(); + } + +} \ No newline at end of file diff --git a/src/main/java/net/romvoid/crashbot/file/solution/SolutionFile.java b/src/main/java/net/romvoid/crashbot/file/solution/SolutionFile.java new file mode 100644 index 0000000..0204595 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/file/solution/SolutionFile.java @@ -0,0 +1,55 @@ +package net.romvoid.crashbot.file.solution; + +import java.io.Reader; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +public class SolutionFile { + + private static List solutions = new ArrayList(); + private static Gson gson = new GsonBuilder().setPrettyPrinting().create(); + private static Writer writer; + private static Reader reader; + + public static List read() { + try { + reader = Files.newBufferedReader(Paths.get("solutions/solutions.json")); + //setSolutions(gson.fromJson(reader, new TypeToken>() {}.getType())); + List list = Arrays.asList(gson.fromJson(reader, Solution[].class)); + reader.close(); + return list; + } catch (Exception e) { + e.getStackTrace(); + } + return null; + } + + public static void write(Solution solution) { + solutions.addAll(getSolutions()); + solutions.add(solution); + try { + + writer = Files.newBufferedWriter(Paths.get("solutions/solutions.json")); + gson.toJson(solutions, writer); + for(Solution s : solutions) { + System.out.println(s.toString()); + } + writer.close(); + } catch (Exception e) { + e.getStackTrace(); + } + } + + + public static List getSolutions() { + solutions = read(); + return solutions; + } +} diff --git a/src/main/java/net/romvoid/crashbot/logging/InverseThresholdFilter.java b/src/main/java/net/romvoid/crashbot/logging/InverseThresholdFilter.java new file mode 100644 index 0000000..00d1255 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/logging/InverseThresholdFilter.java @@ -0,0 +1,34 @@ +package net.romvoid.crashbot.logging; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.filter.Filter; +import ch.qos.logback.core.spi.FilterReply; + +public class InverseThresholdFilter extends Filter { + protected Level level; + + @Override + public FilterReply decide(ILoggingEvent event) { + if (!isStarted()) { + return FilterReply.NEUTRAL; + } + + if (event.getLevel().isGreaterOrEqual(level)) { + return FilterReply.DENY; + } else { + return FilterReply.NEUTRAL; + } + } + + public void setLevel(String level) { + this.level = Level.toLevel(level); + } + + @Override + public void start() { + if (this.level != null) { + super.start(); + } + } +} diff --git a/src/main/java/net/romvoid/crashbot/utilities/Colors.java b/src/main/java/net/romvoid/crashbot/utilities/Colors.java new file mode 100644 index 0000000..ac137b4 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/utilities/Colors.java @@ -0,0 +1,54 @@ +package net.romvoid.crashbot.utilities; + +import java.awt.Color; + +public class Colors { + + /** + * Universal Colors to use for Embeds + * + * TRY TO USE THESE ON MOST EMBEDS + */ + public static class Universal { + + /** + * Primary Embed Color (Light Green) + */ + public static Color PRIMARY = new Color(46, 204, 113); + + /** + * Secondary Embed Color (Light Blue) + */ + public static Color SECONDARY = new Color(41, 128, 185); + + /** + * Error Embed Color (Bright Red) + */ + public static Color ERROR = new Color(231, 76, 60); + + /** + * No Permissions for Command Embed Color (Dark Purple) + */ + public static Color NO_PERMISSION = new Color(75, 31, 94); + + /** + * Command Not Implemented Embed Color (Gold) + */ + public static Color NOT_IMPLEMENTED = new Color(243, 156, 18); + } + + + public static class Custom { + + public static Color Orange = new Color(255, 102, 0); + public static Color Red = new Color(255, 0, 0); + public static Color OrangeYellow = new Color(255, 204, 0); + public static Color LimeGreen = new Color(0, 255, 0); + public static Color Black = new Color(0, 0, 0); + public static Color MidnightBlue = new Color(0, 51, 102); + public static Color RoyalPurple = new Color(102, 51, 153); + public static Color DodgerBlue = new Color(51, 153, 255); + public static Color EmeraldGreen = new Color(85, 212, 63); + public static Color DarkGreen = new Color(58, 95, 11); + } +} diff --git a/src/main/java/net/romvoid/crashbot/utilities/EmbedUtil.java b/src/main/java/net/romvoid/crashbot/utilities/EmbedUtil.java new file mode 100644 index 0000000..8570268 --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/utilities/EmbedUtil.java @@ -0,0 +1,165 @@ +package net.romvoid.crashbot.utilities; + +import java.util.concurrent.TimeUnit; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.romvoid.crashbot.Bot; + +/** + * Generates common embed messages. + * + * @author ROMVoid + */ +public class EmbedUtil { + /** + * The default deletion interval. + * TODO: Create a config-option to set this per-guild + */ + private static final long defaultDeleteInterval = 60; + /** + * The default deletion interval TimeUnit. + * TODO: Create a config-option to set this per-guild + */ + private static final TimeUnit defaultDeleteIntervalTimeUnit = TimeUnit.SECONDS; + + /** + * Creates an embedded message indicating a successful feature execution. + * + * @param title the title of the embedded. + * @param description a more detailed description. + * @return the generated EmbedBuilder. + */ + public static EmbedBuilder success(String title, String description) { + return embed(":white_check_mark: " + title, description).setColor(Colors.Universal.PRIMARY); + } + + /** + * Creates an embedded message with additional information. + * + * @param title the title of the embedded. + * @param description a more detailed description. + * @return the generated EmbedBuilder. + */ + public static EmbedBuilder info(String title, String description) { + return embed(":information_source: " + title, description).setColor(Colors.Universal.SECONDARY); + } + + /** + * Creates an embedded unknown error message. + * + * @return the generated EmbedBuilder. + */ + public static EmbedBuilder error() { + return error("Unknown error", "An unknown error occurred."); + } + + /** + * Creates an embedded error message. + * + * @param title the title of the embedded. + * @param description the error description. + * @return the generated EmbedBuilder. + */ + public static EmbedBuilder error(String title, String description) { + return embed(":warning: " + title, description).setColor(Colors.Universal.ERROR); + } + + /** + * Creates an embedded no permissions message. + * + * @return the generated EmbedBuilder. + */ + public static EmbedBuilder no_permissions() { + return embed(":warning: " + "No permissions", "You don't have the permission to execute this command!").setColor(Colors.Universal.NO_PERMISSION); + } + + + /** + * Creates an embedded message. + * + * @param title the title of the embedded. + * @param description the description (main message). + * @return the generated EmbedBuilder. + */ + public static EmbedBuilder embed(String title, String description) { + return new EmbedBuilder().setTitle(title).setDescription(description); + } + + /** + * Attaches a timestamp to an embedded message. + * + * @param embedBuilder the EmbedBuilder to attach a timestamp to. + * @return the given EmbedBuilder with a timestamp. + */ + public static EmbedBuilder withTimestamp(EmbedBuilder embedBuilder) { + return embedBuilder.setFooter(Bot.getNewTimestamp(), null); + } + + /** + * Converts an EmbedBuilder into a message. + * + * @param embedBuilder the EmbedBuilder that contains the embed data. + * @return the compiled Message. + */ + public static Message message(EmbedBuilder embedBuilder) { + return new MessageBuilder().setEmbed(embedBuilder.build()).build(); + } + + /** + * Always sends a message but deletes it only if the messageChannel is on a server. + * + * @param messageChannel the channel to send the message in. + * @param message the message to send. + */ + public static void sendAndDeleteOnGuilds(MessageChannel messageChannel, Message message) { + sendAndDeleteOnGuilds(messageChannel, message, defaultDeleteInterval, defaultDeleteIntervalTimeUnit); + } + + /** + * Always sends a message but deletes it only if the messageChannel is on a server. + * + * @param messageChannel the channel to send the message in. + * @param message the message to send. + * @param deleteInterval the interval after that the message should be deleted if the channel is on a server. + * @param deleteIntervalTimeUnit the TimeUnit of deleteInterval. + */ + public static void sendAndDeleteOnGuilds(MessageChannel messageChannel, Message message, long deleteInterval, TimeUnit deleteIntervalTimeUnit) { + sendAndDelete(messageChannel, message, + // only delete message on servers. + messageChannel.getType() == ChannelType.TEXT ? deleteInterval : -1, + deleteIntervalTimeUnit); + } + + /** + * Sends a message and deletes it after an interval (if interval is >= 0). + * + * @param messageChannel the channel to send the message in. + * @param message the message to send. + * @param deleteInterval the interval after that the message should be deleted. Message won't be deleted if + * interval is < 0. + * @param deleteIntervalTimeUnit the TimeUnit of deleteInterval. + */ + public static void sendAndDelete(MessageChannel messageChannel, Message message, long deleteInterval, TimeUnit deleteIntervalTimeUnit) { + messageChannel.sendMessage(message).queue(deleteInterval < 0 + // do nothing if interval < 0 + ? null + // else: delete after interval + : sentMessage -> sentMessage.delete().queueAfter(deleteInterval, deleteIntervalTimeUnit, null, ignored -> { + //TODO evaluate exception, i.e. bot does not have permission + })); + } + + public static void sendAndDelete(MessageChannel messageChannel, EmbedBuilder embed, long deleteInterval, TimeUnit deleteIntervalTimeUnit) { + messageChannel.sendMessage(embed.build()).queue(deleteInterval < 0 + // do nothing if interval < 0 + ? null + // else: delete after interval + : sentMessage -> sentMessage.delete().queueAfter(deleteInterval, deleteIntervalTimeUnit, null, ignored -> { + //TODO evaluate exception, i.e. bot does not have permission + })); + } +} \ No newline at end of file diff --git a/src/main/java/net/romvoid/crashbot/utilities/HasteUtil.java b/src/main/java/net/romvoid/crashbot/utilities/HasteUtil.java new file mode 100644 index 0000000..a6acceb --- /dev/null +++ b/src/main/java/net/romvoid/crashbot/utilities/HasteUtil.java @@ -0,0 +1,172 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 ROMVoid + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package net.romvoid.crashbot.utilities; + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +import org.json.JSONObject; +import org.jsoup.Connection; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; + +public class HasteUtil { + + /** The hastebin server URL. + * TODO: Create a per-guild config-option to choose a custom URL + * + * */ + private static String HASTEBIN_SERVER = "http://www.mfnd.ru:7775/"; // requires trailing slash + private static URI uri; + + /** + * A simple implementation of the Hastebin Client API, allowing data to be pasted online for + * players to access. + * + * @param urlParameters The string to be sent in the body of the POST request + * @return A formatted URL which links to the pasted file + */ + public synchronized static void paste(String urlParameters) { + HttpURLConnection connection = null; + + try { + //Create connection + URL url = new URL(HASTEBIN_SERVER + "documents"); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestMethod("POST"); + connection.setDoInput(true); + connection.setDoOutput(true); + connection.setConnectTimeout(0); + + //Send request + DataOutputStream wr = new DataOutputStream(connection.getOutputStream()); + wr.writeBytes(urlParameters); + wr.flush(); + wr.close(); + + //Get Response + BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream())); + JSONObject object = new JSONObject(rd.readLine()); + String[] out = object.toString().replace("{", "").replace("}", "").replace("\"", "").split(":"); + String output = HASTEBIN_SERVER + out[1]; + uri = new URI(output + ".crashlog"); + + } catch (IOException | URISyntaxException e) { + + } finally { + + connection.disconnect(); + } + } + + public static URI getLink() { + return uri; + } + + /** + * Returns the URL of the server being used. + * + * @return API to use for posting data + */ + public static String getPasteURL() { + return HASTEBIN_SERVER; + } + + /** + * Sets the URL used by the paste method, allowing for the server logs are pasted to to be + * dynamically changed. + * + * @param URL API URL of HasteBin instance + */ + public static void setPasteURL(String URL) { + HASTEBIN_SERVER = URL; + } + + /** + * Grabs a HasteBin file from the Internet and attempts to return the file with formatting + * intact. + * + * @return String HasteBin Raw Text + */ + public static synchronized String getPaste(String ID) { + String URLString = HASTEBIN_SERVER + "raw/" + ID + "/"; + try { + URL URL = new URL(URLString); + HttpURLConnection connection = (HttpURLConnection) URL.openConnection(); + connection.setDoOutput(true); + connection.setConnectTimeout(0); + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String paste = ""; + while (reader.ready()) { + String line = reader.readLine(); + if (line.contains("package")) continue; + if (paste.equals("")) paste = line; + else paste = paste + "\n" + line; + } + return paste; + } catch (IOException e) { + return ""; + } + } + + public static synchronized String getOtherPaste(String url) { + try { + URL URL = new URL(url); + HttpURLConnection connection = (HttpURLConnection) URL.openConnection(); + connection.setDoOutput(true); + connection.setConnectTimeout(0); + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String paste = ""; + while (reader.ready()) { + String line = reader.readLine(); + if (line.contains("package")) continue; + if (paste.equals("")) paste = line; + else paste = paste + "\n" + line; + uri = new URI(url); + } + return paste; + } catch (IOException | URISyntaxException e) { + return ""; + } + } + + public static synchronized String getCrashFromUbuntuPaste(String url) { + try { + Connection con = Jsoup.connect(url).ignoreHttpErrors(true).timeout(0); + Document doc = con.get(); + Element paste = doc.select("pre").get(1); + return paste.text(); + } catch (IOException e) { + e.printStackTrace(); + } + return ""; + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..4bc0224 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,45 @@ + + + + + + WARN + + + [%d{HH:mm:ss}] [%level] [%logger{0}]: %msg%n + + + + + System.err + + WARN + + + [%d{HH:mm:ss}] [%level] [%logger{0}]: %msg%n + + + + + logs/current.log + + + logs/%d{yyyy-MM-dd}.log + + + 30 + 3GB + + + + + [%d{HH:mm:ss}] [%level] [%logger{0}]: %msg%n + + + + + + + + + \ No newline at end of file