commit 434ebc47030cd19647e39d5b4676540cb7dc98ad Author: Aleksei Date: Thu Feb 13 23:01:27 2020 -0500 Open source release diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eca6160 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +.gradle +build/ +bin/ + +# Ignore any sqlite databases created +*.db + +# Stupid IntelliJ stuff +.idea +*.iml +out/ + +# Stupid VSCode stuff +.vscode + +# Stupid Eclipse project files +.classpath +.project +.settings + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Ignore commandler files +cmdframework.db +config.properties + +# Ignore the bot config +bot.config \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..8e42ecf --- /dev/null +++ b/build.gradle @@ -0,0 +1,33 @@ +/* + * Developed by Alek Gryczewski on 10/18/18 1:39 PM + * Last modified 9/25/18 7:33 PM + * Copyright (c) 2018. All rights reserved. + */ + +plugins { + id 'application' +} + +group 'studio.spiderling' +version '1.1.11' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() + maven { + url 'https://jitpack.io' + } +} + +dependencies { + + implementation 'com.github.Kaaz:ConfigurationBuilder:0.4' + implementation group: 'org.javacord', name: 'javacord', version:'3.0.5' + implementation group: 'com.rethinkdb', name: 'rethinkdb-driver', version: '2.3.3' + implementation 'com.vdurmont:emoji-java:4.0.0' + + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +mainClassName = 'dev.salmonllama.fsbot.Main' diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..1948b90 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..d0edec2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,12 @@ +# +# Developed by Alek Gryczewski on 10/18/18 1:39 PM +# Last modified 8/10/18 4:16 AM +# Copyright (c) 2018. All rights reserved. +# + +#Fri Aug 10 04:16:52 EDT 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..cccdd3d --- /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="" + +# 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..f955316 --- /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= + +@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/profilePic.png b/profilePic.png new file mode 100644 index 0000000..3ee8de7 Binary files /dev/null and b/profilePic.png differ diff --git a/profilePicDEV.png b/profilePicDEV.png new file mode 100644 index 0000000..f8a0d66 Binary files /dev/null and b/profilePicDEV.png differ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..79b3ef2 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,8 @@ +/* + * Developed by Alek Gryczewski on 10/18/18 1:39 PM + * Last modified 8/27/18 6:45 PM + * Copyright (c) 2018. All rights reserved. + */ + +rootProject.name = 'fsbot' + diff --git a/src/main/java/dev/salmonllama/fsbot/Main.java b/src/main/java/dev/salmonllama/fsbot/Main.java new file mode 100644 index 0000000..cc9251b --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/Main.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot; + +import com.rethinkdb.RethinkDB; +import com.rethinkdb.net.Connection; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Guthix; +import dev.salmonllama.fsbot.listeners.*; +import org.javacord.api.DiscordApiBuilder; + +import dev.salmonllama.fsbot.utilities.Constants; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; + + +// TODO: auto-switching status messages. +// TODO: Add an official Logger --> logging to Discord, not console + +public class Main { + + public static void main(String[] args) { + String configLocation = Constants.BOT_FOLDER.concat(Constants.CONFIG_NAME); + BotConfig.initConfig(configLocation); + + // Initialise the database with values from the bot's config file + RethinkDB r = RethinkDB.r; + Connection conn = r.connection().hostname(BotConfig.DB_HOST).port(BotConfig.DB_PORT).connect(); + + new DiscordApiBuilder().setToken(BotConfig.TOKEN).login().thenAccept(api -> { + DatabaseUtilities db = new DatabaseUtilities(r, conn, api); + db.tableSetup(); + + Guthix guthix = new Guthix(api, db); + + // Register listeners + api.addMessageCreateListener(new ImageListener(r, conn)); + api.addServerMemberJoinListener(new NewMemberListener(api)); + api.addServerJoinListener(new ServerJoined(api, db)); + api.addMessageCreateListener(new ThumbsListener()); + api.addMessageCreateListener(new AchievementListener()); + api.addMessageCreateListener(new ReportListener()); + + System.out.println(String.format("Bot invite: %s", api.createBotInvite())); + System.out.println(String.format("Logged in as %s", api.getYourself().getDiscriminatedName())); + }); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/CreateGalleryCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/CreateGalleryCommand.java new file mode 100644 index 0000000..76b7407 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/CreateGalleryCommand.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.developer; + +import com.rethinkdb.RethinkDB; +import com.rethinkdb.net.Connection; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.server.Server; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class CreateGalleryCommand extends Command { // TODO: This command needs help. + @Override public String name() { return "Create Gallery"; } + @Override public String description() { return "Creates a channel gallery, tracking any posted images"; } + @Override public String usage() { return "creategallery "; } + @Override public String category() { return "Developer"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.OWNER); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("creategallery", "addgallery", "addgall")); } + + static final RethinkDB R = RethinkDB.r; + static final Connection CONN = R.connection().hostname("localhost").port(28015).connect(); + + @Override + public void onCommand(CommandContext ctx) { + Server server = ctx.getServer(); + TextChannel channel = ctx.getChannel(); + String[] args = ctx.getArgs(); + String targetChannelId = channel.getIdAsString(); + String targetChannelName = channel.asServerChannel().get().getName(); // TODO: un-band-aid this. + String targetServerName = server.getName(); + String targetServerId = server.getIdAsString(); + + if (!server.getIdAsString().equals(BotConfig.HOME_SERVER)) { + channel.sendMessage("Fashion galleries can only be created in the Fashionscape server"); + return; + } + + if (args.length < 1) { + channel.sendMessage("No Arguments provided"); + return; + } + else if (args.length > 1) { + channel.sendMessage("Too many arguments provided."); + return; + } + + String tag = args[0]; + + if (R.db("fsbot").table("channels").getField("cId").contains(targetChannelId).run(CONN)) { + EmbedBuilder embed = new EmbedBuilder() + .setColor(Color.RED) + .addField("ERROR", "This channel is already gathering images"); + channel.sendMessage(embed); + } + else { + R.db("fsbot").table("channels").insert( + R.hashMap("sName", targetServerName) + .with("sId", targetServerId) + .with("cName", targetChannelName) + .with("cId", targetChannelId) + .with("tag", tag) + ).run(CONN); + + R.db("fsbot").tableCreate(tag).run(CONN); + + EmbedBuilder embed = new EmbedBuilder() + .setColor(Color.GREEN) + .addField("Success", "Channel added to storage with the following values:") + .addField("Channel Name:", targetChannelName) + .addField("Channel Id:", targetChannelId) + .addField("Tag:", tag) + .addField("End:", String.format("Table \"%s\" created for images in this channel", tag)); + channel.sendMessage(embed); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/EvalCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/EvalCommand.java new file mode 100644 index 0000000..517e20f --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/EvalCommand.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.developer; + +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class EvalCommand extends Command { + @Override public String name() { return "Eval"; } + @Override public String description() { return "Evaluates the given parameters"; } + @Override public String usage() { return "eval "; } + @Override public String category() { return "Developer"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.OWNER); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("eval", "ev")); } + + private final DatabaseUtilities db; + + public EvalCommand(DatabaseUtilities db) { + this.db = db; + } + + @Override + public void onCommand(CommandContext ctx) { + String statement = String.join(" ", ctx.getArgs()); + + ScriptEngineManager factory = new ScriptEngineManager(); + ScriptEngine engine = factory.getEngineByName("JavaScript"); + + engine.put("db", db); + + try { + Object result = engine.eval(statement); + ctx.reply(result.toString()); + } + catch (Exception e) { + ctx.reply(e.getMessage()); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/InviteCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/InviteCommand.java new file mode 100644 index 0000000..5bc4afc --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/InviteCommand.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.developer; + +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.channel.TextChannel; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class InviteCommand extends Command { + @Override public String name() { return "Invite"; } + @Override public String description() { return "Spits out a bot invite"; } + @Override public String usage() { return "invite"; } + @Override public String category() { return "Developer"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.OWNER); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("invite", "inv")); } + + @Override + public void onCommand(CommandContext ctx) { + TextChannel channel = ctx.getChannel(); + DiscordApi api = ctx.getApi(); + + channel.sendMessage(String.format("<%s>", api.createBotInvite())); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java new file mode 100644 index 0000000..295fe87 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.developer; + +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class TestCommand extends Command { + @Override public String name() { return "Test"; } + @Override public String description() { return "A test command"; } + @Override public String usage() { return "test"; } + @Override public String category() { return "Developer"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.OWNER); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("test", "t")); } + + @Override + public void onCommand(CommandContext ctx) { + ctx.getChannel().sendMessage("Test Command has been invoked"); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java new file mode 100644 index 0000000..40406d7 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.general; + +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import dev.salmonllama.fsbot.utilities.ColorRole; +import dev.salmonllama.fsbot.utilities.database.RoleColourUtility; +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.permission.Role; +import org.javacord.api.entity.server.Server; +import dev.salmonllama.fsbot.utilities.warnings.Warning; +import org.javacord.api.entity.user.User; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class ColorCommand extends Command { + @Override public String name() { return "Color"; } + @Override public String description() { return "Assigns the provided cosmetic role"; } + @Override public String usage() { return "color "; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("color", "colour")); } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + DiscordApi api = ctx.getApi(); + Server server = ctx.getServer(); + User user = ctx.getUser(); + TextChannel channel = ctx.getChannel(); + + // Live server + if (!server.getIdAsString().equals(BotConfig.HOME_SERVER)) { return; } + + if (!user.getRoles(server).contains(server.getRoleById(BotConfig.HYDRIX_ROLE).orElseThrow(AssertionError::new))) { + channel.sendMessage(new Warning("You need the Hydrix role to use this").sendWarning()); + return; + } + + if (args.length != 1) { + channel.sendMessage(new Warning("Not enough arguments provided").sendWarning()); + return; + } + + // args[0] is the subcommand, either list, or a colour + if (args[0].equals("list")) { + System.out.println(RoleColourUtility.getAllRoleInfo()); + return; + } + + String roleId = RoleColourUtility.getColour(args[0]); + Role role; + + if (!api.getRoleById(roleId).isPresent()) { + channel.sendMessage(new Warning("That role doesn't exist, mate!").sendWarning()); + return; + } + else { + role = api.getRoleById(roleId).get(); + } + + // Actual command logic now + + // Remove all the colour roles from the user, except the target one + List allRoles = RoleColourUtility.getAllRoles(); + allRoles.forEach(r -> { + if (r.id.equals(roleId)) { + server.removeRoleFromUser(user, server.getRoleById(r.id).orElseThrow(AssertionError::new)); + } + }); + + // If user already has the role, remove it + if (user.getRoles(server).contains(role)) { + user.removeRole(role); + channel.sendMessage(new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle("Role Removed") + .addInlineField("Role:", role.getName()) + ); + } + else { + user.addRole(role); + channel.sendMessage(new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle("Role Added") + .addInlineField("Role:", role.getName()) + ); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java new file mode 100644 index 0000000..dd9b8da --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.general; + +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.server.Server; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.utilities.ColorRole; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class ColorsCommand extends Command { + @Override public String name() { return "Colors"; } + @Override public String description() { return "Lists available cosmetic roles"; } + @Override public String usage() { return "colors"; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("colors", "colours")); } + + @Override + public void onCommand(CommandContext ctx) { + Server server = ctx.getServer(); + TextChannel channel = ctx.getChannel(); + + if (!server.getIdAsString().equals(BotConfig.HOME_SERVER)) { + return; + } + + channel.sendMessage(ColorRole.rolesListEmbed()); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/HelpCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/HelpCommand.java new file mode 100644 index 0000000..ccc5f92 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/HelpCommand.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.general; + +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.*; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.embed.EmbedBuilder; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + + +public class HelpCommand extends Command { + @Override public String name() { return "Help"; } + @Override public String description() { return "Shows all commands, or a specific command's information"; } + @Override public String usage() { return "help [String command]"; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("help", "h")); } + + private final Guthix guthix; + + public HelpCommand(Guthix guthix) { + this.guthix = guthix; + } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + TextChannel channel = ctx.getChannel(); + + String prefix = BotConfig.DEFAULT_PREFIX; + + if (args.length == 0) { + channel.sendMessage(buildCategoryHelp(prefix)); + } + if (args.length == 1) { + if (isCategory(args[0])) { + channel.sendMessage(buildTargetCategory(prefix, args[0])); + } + else if (isCommand(args[0])) { + channel.sendMessage(buildCommandHelp(channel, prefix, args[0])); + } + else { + channel.sendMessage("No match found"); + } + } + } + + private EmbedBuilder buildCategoryHelp(String prefix) { + StringBuilder builder = new StringBuilder(); + builder.append("```yml"); + List categories = new ArrayList<>(); + + for (Command cmd : guthix.listCommands()) { + String category = cmd.category(); + if (!categories.contains(category)) { + categories.add(category); + + builder.append("\n -").append(category); + } + } + + builder.append("```"); + + return new EmbedBuilder() + .setTitle("Command Categories") + .setColor(Color.GREEN) + .addField("Prefix", String.format("```%s```", prefix)) + .addField("Categories", builder.toString()) + .setFooter(String.format("Use `%shelp to see commands in the category", prefix)); + } + + private EmbedBuilder buildTargetCategory(String prefix, String category) { + StringBuilder builder = new StringBuilder().append("```yml"); + + for (Command cmd : guthix.listCommands()) { + String cat = cmd.category().toLowerCase(); + if (cat.equals(category.toLowerCase())) { + builder.append("\n- ").append(cmd.name()); + } + } + + builder.append("```"); + + return new EmbedBuilder() + .setTitle(String.format("%s Commands", category)) + .setColor(Color.GREEN) + .addField("Prefix", String.format("```%s```", prefix)) + .addField("Commands:", builder.toString()) + .setFooter(String.format("Use `%shelp to see command info", prefix)); + } + + private EmbedBuilder buildCommandHelp(TextChannel channel, String prefix, String command) { + + String targetedCommand = null; + Collection targetedAliases = null; + String targetedDescription = null; + String targetedUsage = null; + CommandPermission targetedPermissions = null; // TODO: Make a toString() method for this eh? + + for (Command cmd : guthix.listCommands()) { + for (String alias : cmd.aliases()) { + if (alias.equals(command)) { + targetedCommand = cmd.name(); + targetedAliases = cmd.aliases(); + targetedDescription = cmd.description(); + targetedUsage = cmd.usage(); + targetedPermissions = cmd.permission(); + } + } + } + + if (targetedCommand == null) { + return new EmbedBuilder() + .setColor(Color.RED) + .addField("ERROR:", "That command does not exist"); + } + + StringBuilder builder = new StringBuilder(); + builder.append("```yml\n"); + + if (targetedAliases.size() != 0) { + builder.append(String.format("- Aliases: %s\n", String.join(", ", targetedAliases))); + } + if (!targetedDescription.equals("none")) { + builder.append(String.format("- Description: %s\n", targetedDescription)); + } + if (!targetedUsage.equals("")) { + builder.append(String.format("- Usage: %s\n", targetedUsage)); + } + builder.append(String.format("- Permissions: %s\n", targetedPermissions)); + + builder.append("```"); + + return new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle(String.format("%s%s", prefix, targetedCommand)) + .setDescription(builder.toString()); + } + + public boolean isCommand(String input) { + for (Command cmd : guthix.listCommands()) { + Collection aliases = cmd.aliases(); + for (String alias : aliases) { + if (alias.toLowerCase().equals(input.toLowerCase())) { + return true; + } + } + } + + return false; + } + + public boolean isCategory(String input) { + for (Command cmd : guthix.listCommands()) { + String category = cmd.category(); + if (category.toLowerCase().equals(input.toLowerCase())) { + return true; + } + } + + return false; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/OutfitCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/OutfitCommand.java new file mode 100644 index 0000000..b152310 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/OutfitCommand.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.general; + +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.Message; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class OutfitCommand extends Command { + @Override public String name() { return "Outfit"; } + @Override public String description() { return "Generates a random image with the given tag. Use ~tags to see valid tags."; } + @Override public String usage() { return "outfit "; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("outfit", "o")); } + + private final DatabaseUtilities db; + + public OutfitCommand(DatabaseUtilities db) { + this.db = db; + } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + TextChannel channel = ctx.getChannel(); + Message message = ctx.getMessage(); + // Find the first arg for tag/submitter/naught, find the next arg for number to send + + int MAX_OUTFITS = 5; + + if (args.length == 0) { + channel.sendMessage(db.randomOutfit().generateEmbed()); + } + else if (message.getMentionedUsers().size() > 0) { + // Outfit needs to be from submitter + String userId = message.getMentionedUsers().get(0).getIdAsString(); + + if (args.length == 2) { + // Send a number of outfits + int iterator = ((Integer.parseInt(args[1]) > MAX_OUTFITS) ? MAX_OUTFITS : Integer.parseInt(args[1])); + + for (int i = 0; i < iterator; i++) { + channel.sendMessage(db.getOutfitBySubmitter(userId).generateEmbed()); + } + } + else { + channel.sendMessage(db.getOutfitBySubmitter(userId).generateEmbed()); + } + } + else if (db.getTags().contains(args[0].toLowerCase())) { + // Outfit needs to be tagged + String tag = args[0]; + + if (args.length == 2) { + // Send a number of outfits + int iterator = ((Integer.parseInt(args[1]) > MAX_OUTFITS) ? MAX_OUTFITS : Integer.parseInt(args[1])); + + for (int i = 0; i < iterator; i++) { + channel.sendMessage(db.randomTaggedOutfit(tag).generateEmbed()); + } + } + else { + channel.sendMessage(db.randomTaggedOutfit(tag).generateEmbed()); + } + } + else if (args.length == 1 && args[0].matches("\\d")) { + int iterator = ((Integer.parseInt(args[0]) > MAX_OUTFITS) ? MAX_OUTFITS : Integer.parseInt(args[0])); + + for (int i = 0; i < iterator; i++) { + channel.sendMessage(db.randomOutfit().generateEmbed()); + } + } + else { + channel.sendMessage("Something went wrong"); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/PingCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/PingCommand.java new file mode 100644 index 0000000..5ef8811 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/PingCommand.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.general; + +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; + +import java.util.*; + +public class PingCommand extends Command { + @Override public String name() { return "Ping"; } + @Override public String description() { return "Pings the bot, checks for a heartbeat"; } + @Override public String usage() { return "ping"; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return new ArrayList<>(Collections.singletonList("ping")); } + + @Override + public void onCommand(CommandContext ctx) { + final long start = System.currentTimeMillis(); + + ctx.getChannel().sendMessage("I'm alive").thenAccept(msg -> { + final long end = System.currentTimeMillis(); + msg.edit(String.format("I'm alive! (%sms)", (end - start))); + }); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/SpecificOutfitCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/SpecificOutfitCommand.java new file mode 100644 index 0000000..f80087a --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/SpecificOutfitCommand.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.general; + +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.entity.channel.ServerTextChannel; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; +import org.javacord.api.entity.channel.TextChannel; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.ArrayBlockingQueue; + +public class SpecificOutfitCommand extends Command { + @Override public String name() { return "Specific Outfit"; } + @Override public String description() { return "Generates an outfit of a specific tag"; } + @Override public String usage() { return " [int number]"; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return new ArrayList<>(db.getTags()); } + + private final DatabaseUtilities db; + + public SpecificOutfitCommand(DatabaseUtilities db) { + this.db = db; + } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + String tag = ctx.getUsedAlias(); + TextChannel channel = ctx.getChannel(); + + if (args.length == 1) { + // Send the specific number of outfits with a max of 5 + int outfitNumber = Integer.parseInt(args[0]); + if (outfitNumber > 5) { outfitNumber = 5; } + + for (int i = 0; i < outfitNumber; i++) { + channel.sendMessage(db.randomTaggedOutfit(tag).generateEmbed()); + } + } + else if (args.length > 1) { + channel.sendMessage("You did that wrong, mate"); + } + else { + channel.sendMessage(db.randomTaggedOutfit(tag).generateEmbed()); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java new file mode 100644 index 0000000..436b734 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import dev.salmonllama.fsbot.utilities.database.RoleColourUtility; +import dev.salmonllama.fsbot.utilities.warnings.Warning; +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.permission.Role; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class AddColorCommand extends Command { + @Override public String name() { return "Add Color"; } + @Override public String description() { return "adds the provided role to the toggleable cosmetic roles."; } + @Override public String usage() { return "addcolor "; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("addcolor", "addcolour", "addclr")); } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = (String[]) ctx.getArgs(); + TextChannel channel = ctx.getChannel(); + DiscordApi api = ctx.getApi(); + + if (args.length != 2) { + channel.sendMessage(new Warning("Insufficient arguments").sendWarning()); + return; + } + + String colour = args[0]; + String id = args[1]; + + Role role = api.getRoleById(args[1]).orElse(null); + if (role == null) { + channel.sendMessage(new Warning("Supplied roleId isn't a roleId").sendWarning()); + return; + } + + RoleColourUtility.addColourRole(colour, id); + + channel.sendMessage(new EmbedBuilder() + .setTitle(role.getName()) + .setColor(role.getColor().orElse(Color.GREEN)) + .addField("Role id:", role.getIdAsString()) + .addField("Colour to be stored as:", args[0]) + ); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/EchoCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/EchoCommand.java new file mode 100644 index 0000000..0ee01d5 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/EchoCommand.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +public class EchoCommand extends Command { + @Override public String name() { return "Echo"; } + @Override public String description() { return "Echos your message. Typical bash"; } + @Override public String usage() { return "echo "; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Collections.singletonList("echo")); } + + @Override + public void onCommand(CommandContext ctx) { + String echoMessage = String.join(" ", ctx.getArgs()); + + ctx.getMessage().delete(); + + ctx.reply(echoMessage); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java new file mode 100644 index 0000000..45c1c0e --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import com.rethinkdb.RethinkDB; +import com.rethinkdb.net.Connection; +import com.rethinkdb.net.Cursor; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.embed.EmbedBuilder; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class GetOutfitCommand extends Command { // TODO: This command also needs HELP + @Override public String name() { return "Get Outift"; } + @Override public String description() { return "Shows the outfit, given an ID"; } + @Override public String usage() { return "getoutfit "; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("getoutfit", "get")); } + + static final RethinkDB r = RethinkDB.r; + static final Connection conn = r.connection().hostname("localhost").port(28015).connect(); + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + TextChannel channel = ctx.getChannel(); + + if (args.length != 1) { + channel.sendMessage("you did that wrong mate"); + return; + } + + String id = args[0]; + + // Check if the given id exists in the table + try { + r.db("fsbot").table("outfits").filter(row -> row.getField("id").eq(id)).run(conn); + } + catch (Exception e) { + EmbedBuilder embed = new EmbedBuilder() + .setColor(Color.RED) + .addField("ERROR:", "That id does not exist in that table") + .addField("Output:", e.toString()) + .setFooter("Contact Salmonllama#5727 if you see this"); + channel.sendMessage(embed); + return; + } + + // Get the entry for the given table/tag and id, build the embed, and send it. + try { + + String embedLink = null; + String embedSubmitter = null; + + Cursor linkCursor = r.db("fsbot") + .table("outfits") + .filter(row -> row.getField("id").eq(id)) + .getField("link") + .run(conn); + + Cursor submitterCursor = r.db("fsbot") + .table("outfits") + .filter(row -> row.getField("id").eq(id)) + .getField("submitter") + .run(conn); + + List links = linkCursor.toList(); + for (Object link : links) { + embedLink = link.toString(); + } + + List submitters = submitterCursor.toList(); + for (Object submitter : submitters) { + embedSubmitter = submitter.toString(); + } + + // Send a diff message if any of the things are null + if (embedLink == null) { + EmbedBuilder embed = new EmbedBuilder() + .setColor(Color.RED) + .addField("ERROR: ", "The entry you tried to access doesn't exist."); + channel.sendMessage(embed); + return; + } + + // Send the final Embed with the outfit image as a link, the submitter, and the id of the image. + EmbedBuilder embed = new EmbedBuilder() + .setColor(Color.GREEN) + .setAuthor(embedSubmitter) + .setImage(embedLink) + .setFooter(id); + channel.sendMessage(embed); + } + catch (Exception e) { + EmbedBuilder embed = new EmbedBuilder() + .setColor(Color.RED) + .addField("ERROR:", "Something went wrong...") + .addField("Output:", e.toString()) + .setFooter("Contact Crablet#9999 and show him this error."); + channel.sendMessage(embed); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/GetServersCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetServersCommand.java new file mode 100644 index 0000000..938f2a9 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetServersCommand.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.server.Server; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class GetServersCommand extends Command { + @Override public String name() { return "Get Servers"; } + @Override public String description() { return "Lists all the servers the bot is in"; } + @Override public String usage() { return "getservers"; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("getservers", "servers")); } + + @Override + public void onCommand(CommandContext ctx) { + DiscordApi api = ctx.getApi(); + + StringBuilder builder = new StringBuilder(); + builder.append("```md"); + + for (Server server : api.getServers()) { + String serverId = server.getIdAsString(); + String serverName = server.getName(); + + builder.append(String.format("\n- %s: %s", serverName, serverId)); + } + + builder.append("\n```"); + + EmbedBuilder embed = new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle("Servers") + .setDescription(builder.toString()) + .setFooter(String.format("%s is in %d servers", api.getYourself().getName(), api.getServers().size())); + + ctx.getChannel().sendMessage(embed).join(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/OutfitInfoCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/OutfitInfoCommand.java new file mode 100644 index 0000000..5b9bd96 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/OutfitInfoCommand.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.DiscordApi; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; +import dev.salmonllama.fsbot.utilities.exceptions.DiscordError; +import dev.salmonllama.fsbot.utilities.exceptions.OutfitNotFoundException; +import org.javacord.api.entity.channel.TextChannel; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class OutfitInfoCommand extends Command { + @Override public String name() { return "Outfit Info"; } + @Override public String description() { return "Shows all related info about the outfit"; } + @Override public String usage() { return "outfitinfo "; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("outfitinfo", "oinfo")); } + + private final DatabaseUtilities db; + + public OutfitInfoCommand(DatabaseUtilities db) { + this.db = db; + } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + DiscordApi api = ctx.getApi(); + TextChannel channel = ctx.getChannel(); + + if (args.length != 1) { + channel.sendMessage(String.format("you did that wrong. bother %s to make these more specific.", api.getOwner().join().getDiscriminatedName())); + return; + } + + try { + channel.sendMessage(db.getOutfitFromId(args[0]).generateInfo()); + } + catch (OutfitNotFoundException e) { + channel.sendMessage(new DiscordError(e.getMessage()).get()); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java new file mode 100644 index 0000000..deb3424 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import com.vdurmont.emoji.EmojiParser; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.user.User; +import dev.salmonllama.fsbot.listeners.ReactionDeleteConfirmationListener; +import dev.salmonllama.fsbot.utilities.Outfit; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; +import dev.salmonllama.fsbot.utilities.exceptions.DiscordError; +import dev.salmonllama.fsbot.utilities.exceptions.OutfitNotFoundException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class RemoveOutfitCommand extends Command { + @Override public String name() { return "Remove Outfit"; } + @Override public String description() { return "Removes an outfit from the database given an id"; } + @Override public String usage() { return "remove "; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("removeoutfit", "remove")); } + + private final DatabaseUtilities db; + + public RemoveOutfitCommand(DatabaseUtilities db) { + this.db = db; + } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + TextChannel channel = ctx.getChannel(); + User author = ctx.getUser(); + + if (args.length != 1) { + channel.sendMessage("You did that wrong, mate"); + return; + } + + // get the outfit, confirm deletion through reaction. + try { + Outfit outfit = db.getOutfitFromId(args[0]); + + channel.sendMessage(outfit.generateInfo().setTitle("Confirm Outfit Deletion")).thenAccept(message -> { + message.addReaction(EmojiParser.parseToUnicode(":white_check_mark:")); + message.addReaction(EmojiParser.parseToUnicode(":octagonal_sign:")); + message.addReactionAddListener(new ReactionDeleteConfirmationListener(author, message, outfit, db)); + }); + } + catch (OutfitNotFoundException e) { + channel.sendMessage(new DiscordError(e.getMessage()).get()); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java new file mode 100644 index 0000000..ee9f059 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import com.vdurmont.emoji.EmojiParser; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.user.User; +import dev.salmonllama.fsbot.listeners.ReactionRetagConfirmationListener; +import dev.salmonllama.fsbot.utilities.Outfit; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; +import dev.salmonllama.fsbot.utilities.exceptions.DiscordError; +import dev.salmonllama.fsbot.utilities.exceptions.OutfitNotFoundException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +public class RetagCommand extends Command { + @Override public String name() { return "Retag"; } + @Override public String description() { return "Changes the tag of the given outfit"; } + @Override public String usage() { return "retag "; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Collections.singletonList("retag")); } + + private final DatabaseUtilities db; + + public RetagCommand(DatabaseUtilities db) { + this.db = db; + } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + TextChannel channel = ctx.getChannel(); + User author = ctx.getUser(); + + if (args.length != 2) { + channel.sendMessage("You did that wrong mate. check the help command."); + return; + } + + try { + Outfit outfit = this.db.getOutfitFromId(args[0]); + + channel.sendMessage(outfit.generateInfo().setTitle(String.format("Update tag to %s?", args[1]))).thenAcceptAsync(message -> { + message.addReaction(EmojiParser.parseToUnicode(":white_check_mark:")); + message.addReaction(EmojiParser.parseToUnicode(":octagonal_sign:")); + message.addReactionAddListener(new ReactionRetagConfirmationListener(author, message, outfit, db, outfit.getTag(), args[1])); + }); + } + catch (OutfitNotFoundException e) { + channel.sendMessage(new DiscordError(e.getMessage()).get()); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/SetStatusCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/SetStatusCommand.java new file mode 100644 index 0000000..8ab296c --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/SetStatusCommand.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import com.vdurmont.emoji.EmojiParser; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import org.javacord.api.entity.message.embed.EmbedBuilder; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class SetStatusCommand extends Command { + @Override public String name() { return "Set Status"; } + @Override public String description() { return "Updates the bot's current status"; } + @Override public String usage() { return "updatestatus "; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("setstatus", "status")); } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + + // argument checking + if (args.length == 0) { + EmbedBuilder embed = new EmbedBuilder() + .setColor(Color.YELLOW) + .addField("WARNING", "Not enough arguments supplied"); + ctx.getChannel().sendMessage(embed); + return; + } + + String status = String.join(" ", args); + + ctx.getApi().updateActivity(status); + + ctx.getMessage().addReaction(EmojiParser.parseToUnicode(":white_check_mark:")); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java new file mode 100644 index 0000000..c1b502a --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.staff; + +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; +import dev.salmonllama.fsbot.utilities.database.ServerConfUtility; +import dev.salmonllama.fsbot.utilities.warnings.Warning; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.server.Server; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class WelcomeMessageCommand extends Command { + @Override public String name() { return "Welcome Message"; } + @Override public String description() { return "View or update the server welcome message. Options: get|set|getchannel|setchannel."; } + @Override public String usage() { return "welcomemessage [String newMessage]"; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.ROLE, BotConfig.STAFF_ROLE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("welcomemessage", "wmsg")); } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + TextChannel channel = ctx.getChannel(); + Server server = ctx.getServer(); + + if (!server.getIdAsString().equals(BotConfig.HOME_SERVER)) { + return; + } + + if (args.length == 0) channel.sendMessage(new Warning("Not enough arguments provided").sendWarning()); + + switch (args[0]) { + case ("get"): + channel.sendMessage(fetchWelcomeMsg(server)); + break; + case ("set"): + StringBuilder sb = new StringBuilder(); + for (int i = 1; i < args.length; i++) { + sb.append(String.format("%s ", args[i])); + } + + channel.sendMessage(updateWelcomeMsg(sb.toString(), server)); + break; + case ("getchannel"): + channel.sendMessage(fetchWelcomeChannel(server)); + break; + case ("setchannel"): + if (args.length < 2) channel.sendMessage(new Warning("Not enough arguments provided").sendWarning()); + + channel.sendMessage(updateWelcomeChannel(args[1], server)); + break; + } + } + + private EmbedBuilder fetchWelcomeMsg(Server server) { + + ServerConfUtility conf = new ServerConfUtility(server.getIdAsString()); + String msg = conf.getWelcomeMsg(); + + return new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle("Current welcome message:") + .setDescription(msg); + } + + private EmbedBuilder updateWelcomeMsg(String msg, Server server) { + + ServerConfUtility conf = new ServerConfUtility(server.getIdAsString()); + conf.setWelcomeMsg(msg); + + return new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle("Welcome message updated") + .addField("New welcome message:", msg); + } + + private EmbedBuilder fetchWelcomeChannel(Server server) { + + ServerConfUtility conf = new ServerConfUtility(server.getIdAsString()); + String welcomeChannel = conf.getWelcomeChannel(); + + return new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle("Current welcome channel:") + .setDescription(welcomeChannel); + } + + private EmbedBuilder updateWelcomeChannel(String id, Server server) { + + ServerConfUtility conf = new ServerConfUtility(server.getIdAsString()); + conf.setWelcomeChannel(id); + + return new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle("Welcome channel updated:") + .addField("New welcome channel:", id); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java b/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java new file mode 100644 index 0000000..180e55f --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.config; + +import com.kaaz.configuration.ConfigurationBuilder; +import com.kaaz.configuration.ConfigurationOption; + +import java.io.File; + +public class BotConfig { + @ConfigurationOption + public static String TOKEN = "token-goes-here"; + + @ConfigurationOption + public static String DB_HOST = "localhost"; + + @ConfigurationOption + public static int DB_PORT = 28015; + + @ConfigurationOption + public static String DEFAULT_PREFIX = "~"; + + @ConfigurationOption + public static String BOT_OWNER = "owner's id here"; + + @ConfigurationOption + public static String STAFF_ROLE = "staff role id here"; + + @ConfigurationOption + public static String REPORT_CHANNEL = "report channel"; + + @ConfigurationOption + public static String ACHIEVEMENT_CHANNEL = "achievement channel here"; + + @ConfigurationOption + public static String ANNOUNCEMENT_CHANNEL = "announcement channel here"; + + @ConfigurationOption + public static String NEWS_CHANNEL = "news channel here"; + + @ConfigurationOption + public static String VOTE_CHANNEL = "vote channel here"; + + @ConfigurationOption + public static String REPORT_LOG = "report_log_channel"; + + @ConfigurationOption + public static String OUTFIT_LOG = "outfit log channel"; + + @ConfigurationOption + public static String BOT_LOG = "bot_log_channel"; + + @ConfigurationOption + public static String HYDRIX_ROLE = "hydrix role id here"; + + @ConfigurationOption + public static String IMGUR_ID = "imgur_id_here"; + + @ConfigurationOption + public static String IMGUR_BEARER = "imgur bearer here"; + + @ConfigurationOption + public static String HOME_SERVER = "340511685024546816"; + + public static void initConfig(String filePath) { + try { + new ConfigurationBuilder(BotConfig.class, new File(filePath)).build(false); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/Command.java b/src/main/java/dev/salmonllama/fsbot/guthix/Command.java new file mode 100644 index 0000000..2479c8a --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/guthix/Command.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.guthix; + +import java.util.Collection; + +public abstract class Command { + public abstract String name(); + public abstract String description(); + public abstract String usage(); + public abstract String category(); + public abstract CommandPermission permission(); + public abstract Collection aliases(); + + public abstract void onCommand(CommandContext ctx); + + public void invoke(final CommandContext ctx) { + Thread thread = new Thread(() -> onCommand(ctx)); + thread.start(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/CommandContext.java b/src/main/java/dev/salmonllama/fsbot/guthix/CommandContext.java new file mode 100644 index 0000000..0fa5aa3 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/guthix/CommandContext.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.guthix; + +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.Message; +import org.javacord.api.entity.message.MessageAuthor; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.permission.Role; +import org.javacord.api.entity.server.Server; +import org.javacord.api.entity.user.User; +import dev.salmonllama.fsbot.config.BotConfig; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +public class CommandContext { + private DiscordApi api; + private Message message; + private MessageAuthor author; + private TextChannel channel; + private Server server; + private Command usedCommand; + private String usedAlias; + private String[] args; + + CommandContext(DiscordApi api, Message message, MessageAuthor author, TextChannel channel, Server server, String alias, Command cmd, String[] args) { + this.api = api; + this.message = message; + this.author = author; + this.channel = channel; + this.server = server; + this.usedCommand = cmd; + this.usedAlias = alias; + this.args = args; + } + + public DiscordApi getApi() { + return api; + } + + public Message getMessage() { + return message; + } + + public MessageAuthor getAuthor() { + return author; + } + + public TextChannel getChannel() { + return channel; + } + + public Server getServer() { + return server; + } + + public Command getUsedCommand() { + return usedCommand; + } + + public String getUsedAlias() { + return usedAlias; + } + + public String[] getArgs() { + return args; + } + + public User getUser() { + if (author.asUser().isPresent()) { + return author.asUser().get(); + } else { + // Log something to discord, I dunno + } + return null; + } + + public Collection getUserRoles() { + User user = getUser(); + return user.getRoles(getServer()); + } + + public boolean isUserOwner() { + return getUser().getIdAsString().equals(BotConfig.BOT_OWNER); + } + + public CompletableFuture reply(String msg) { + return channel.sendMessage(msg); + } + + public CompletableFuture reply(EmbedBuilder embed) { + return channel.sendMessage(embed); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/CommandPermission.java b/src/main/java/dev/salmonllama/fsbot/guthix/CommandPermission.java new file mode 100644 index 0000000..b6ef613 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/guthix/CommandPermission.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.guthix; + +public class CommandPermission { + private PermissionType type; + private String value; + + public CommandPermission(PermissionType type) { + this.type = type; + } + + public CommandPermission(PermissionType type, String value) { + this.type = type; + this.value = value; + } + + public PermissionType getType() { + return type; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/ContextBuilder.java b/src/main/java/dev/salmonllama/fsbot/guthix/ContextBuilder.java new file mode 100644 index 0000000..39f7b04 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/guthix/ContextBuilder.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.guthix; + +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.Message; +import org.javacord.api.entity.message.MessageAuthor; +import org.javacord.api.entity.server.Server; + +import java.util.Collection; + +public class ContextBuilder { + private DiscordApi api; + private Message message; + private MessageAuthor author; + private TextChannel channel; + private Server server; + private Command usedCommand; + private String usedAlias; + private String[] args; + + public ContextBuilder() { + + } + + public ContextBuilder setUsedCommand(Command commandUsed) { + this.usedCommand = commandUsed; + return this; + } + + public ContextBuilder setUsedAlias(String alias) { + this.usedAlias = alias; + return this; + } + + public ContextBuilder setArgs(String[] args) { + this.args = args; + return this; + } + + ContextBuilder setMessage(Message message) { + this.message = message; + return this; + } + + ContextBuilder setAuthor(MessageAuthor author) { + this.author = author; + return this; + } + + ContextBuilder setChannel(TextChannel channel) { + this.channel = channel; + return this; + } + + ContextBuilder setServer(Server server) { + this.server = server; + return this; + } + + ContextBuilder setApi(DiscordApi api) { + this.api = api; + return this; + } + + CommandContext build() { + return new CommandContext(api, message, author, channel, server, usedAlias, usedCommand, args); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/Guthix.java b/src/main/java/dev/salmonllama/fsbot/guthix/Guthix.java new file mode 100644 index 0000000..469817e --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/guthix/Guthix.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.guthix; + +import dev.salmonllama.fsbot.commands.general.HelpCommand; +import dev.salmonllama.fsbot.commands.general.SpecificOutfitCommand; +import dev.salmonllama.fsbot.commands.staff.OutfitInfoCommand; +import dev.salmonllama.fsbot.commands.general.OutfitCommand; +import dev.salmonllama.fsbot.commands.staff.*; +import dev.salmonllama.fsbot.commands.developer.InviteCommand; +import dev.salmonllama.fsbot.commands.developer.CreateGalleryCommand; +import dev.salmonllama.fsbot.commands.general.ColorsCommand; +import dev.salmonllama.fsbot.commands.general.ColorCommand; +import dev.salmonllama.fsbot.commands.general.PingCommand; +import dev.salmonllama.fsbot.commands.developer.EvalCommand; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.Message; +import org.javacord.api.entity.message.MessageAuthor; +import org.javacord.api.entity.server.Server; +import org.javacord.api.event.message.MessageCreateEvent; +import org.javacord.api.listener.message.MessageCreateListener; +import dev.salmonllama.fsbot.commands.developer.TestCommand; + +import java.util.Collection; +import java.util.HashMap; + +/* +* Guthix is Fashionscape Bot's command repository and dispatcher + */ +public class Guthix implements MessageCreateListener { + private DiscordApi api; + private DatabaseUtilities db; + + private Registry registry; + private PermissionManager manager; + + public Guthix(DiscordApi api, DatabaseUtilities db) { + this.api = api; + api.addMessageCreateListener(this); + + this.db = db; + + manager = new PermissionManager(api); + registry = new Registry(); + + initCommands(); + } + + public void initCommands() { + // Developer Commands + addCommand(new TestCommand()); + addCommand(new EvalCommand(db)); + addCommand(new CreateGalleryCommand()); + addCommand(new InviteCommand()); + + // Staff Commands + addCommand(new EchoCommand()); + addCommand(new GetServersCommand()); + addCommand(new AddColorCommand()); + addCommand(new GetOutfitCommand()); + addCommand(new RetagCommand(db)); + addCommand(new RemoveOutfitCommand(db)); + addCommand(new OutfitInfoCommand(db)); + addCommand(new SetStatusCommand()); + addCommand(new WelcomeMessageCommand()); + + // General Commands + addCommand(new PingCommand()); + addCommand(new ColorCommand()); + addCommand(new ColorsCommand()); + addCommand(new OutfitCommand(db)); + addCommand(new SpecificOutfitCommand(db)); + addCommand(new HelpCommand(this)); + } + + public void addCommand(Command cmd) { + registry.addCommand(cmd); +// return cmd; + } + + public Collection listCommands() { + return registry.listCommands(); + } + + public HashMap mapCommands() { + return registry.mapCommands(); + } + + @Override + public void onMessageCreate(MessageCreateEvent event) { + MessageAuthor author = event.getMessageAuthor(); + + if (manager.sourceIsValid(author)) { + + } else { + return; + } + + String content = event.getMessageContent().toLowerCase(); + + if (registry.startsWithPrefix(content)) { + + } else { + return; + } + + String cmdString = registry.commandString(content); + + if (registry.isCommandAlias(cmdString)) { + + } else { + return; + } + + Message msg = event.getMessage(); + TextChannel channel = event.getChannel(); + Server server = event.getServer().orElse(null); + String[] cmdArgs = registry.getCmdArgs(content); + + Command cmd = registry.findCommand(cmdString).orElse(null); // TODO: default command here + CommandContext ctx = new ContextBuilder().setApi(api) + .setServer(server) + .setAuthor(author) + .setChannel(channel) + .setMessage(msg) + .setArgs(cmdArgs) + .setUsedAlias(cmdString) + .setUsedCommand(cmd) + .build(); + + if (manager.hasPermission(cmd.permission(), ctx)) { + + } else { + return; + } + + cmd.invoke(ctx); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/PermissionManager.java b/src/main/java/dev/salmonllama/fsbot/guthix/PermissionManager.java new file mode 100644 index 0000000..9d25e5e --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/guthix/PermissionManager.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.guthix; + +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.message.MessageAuthor; + +public class PermissionManager { + private DiscordApi api; + + public PermissionManager(DiscordApi api) { + this.api = api; + } + + public boolean hasPermission(CommandPermission reqPerm, CommandContext ctx) { + PermissionType permtype = reqPerm.getType(); + + switch (permtype) { + case NONE: + return true; + case ROLE: + // If the author has the role, yes. Doesn't work in DM + return roleHandler(reqPerm.getValue(), ctx); + case OWNER: + // If the author is the owner, yes. + return ownerHandler(ctx); + } + + return false; + } + + private boolean roleHandler(String roleId, CommandContext ctx) { + return ctx.getUserRoles().stream().anyMatch(role -> role.getIdAsString().equals(roleId)); + } + + private boolean ownerHandler(CommandContext ctx) { + return ctx.isUserOwner(); + } + + boolean sourceIsValid(MessageAuthor author) { + return !author.isBotUser() && !author.isWebhook(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/PermissionType.java b/src/main/java/dev/salmonllama/fsbot/guthix/PermissionType.java new file mode 100644 index 0000000..b20e97b --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/guthix/PermissionType.java @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.guthix; + +public enum PermissionType { + ROLE, // User has a specific role inside the server + OWNER, // User is the bot owner + NONE // No requirement +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/Registry.java b/src/main/java/dev/salmonllama/fsbot/guthix/Registry.java new file mode 100644 index 0000000..206d71f --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/guthix/Registry.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.guthix; + +import dev.salmonllama.fsbot.config.BotConfig; + +import java.util.*; +import java.util.function.Predicate; + +class Registry { + private Collection commands; + private HashMap commandsMap; + + Registry() { + commands = new ArrayList<>(); + commandsMap = new HashMap<>(); + } + + Predicate valueMatch(String input) { // TODO: Move to a helper class + return str -> str.equals(input); + } + + Command addCommand(Command cmd) { + commands.add(cmd); + commandsMap.put(cmd.name(), cmd); + return cmd; + } + + Collection listCommands() { + return commands; + } + + HashMap mapCommands() { + return commandsMap; + } + + boolean startsWithPrefix(String input) { + return input.startsWith(BotConfig.DEFAULT_PREFIX); + } + + Collection getCommandAliases() { + Collection aliases = new ArrayList<>(); + + commands.forEach(cmd -> { + aliases.addAll(cmd.aliases()); + }); + + return aliases; + } + + Optional findCommand(String alias) { + for (Command cmd: commands) { + if (cmd.aliases().contains(alias)) { + return Optional.of(cmd); + } + } + return Optional.empty(); + } + + boolean isCommandAlias(String input) { + return getCommandAliases().stream().anyMatch(valueMatch(input)); + } + + String removePrefix(String input) { + int startPoint = BotConfig.DEFAULT_PREFIX.length(); + return input.substring(startPoint); + } + + List splitArgs(String input) { + if (input.contains(" ")) { + input = removePrefix(input); + String[] splits = input.split(" "); + return new ArrayList<>(Arrays.asList(splits)); + } else { + input = removePrefix(input); + return new ArrayList<>(Collections.singletonList(input)); + } + } + + String[] getCmdArgs(String input) { + List splits = splitArgs(input); + splits.remove(0); + return splits.toArray(new String[0]); + } + + String commandString(String input) { + // Cleans the string of the prefix and any args, returning only the command + return splitArgs(input).get(0); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/AchievementListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/AchievementListener.java new file mode 100644 index 0000000..1e4cd15 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/listeners/AchievementListener.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.listeners; + +import com.vdurmont.emoji.EmojiParser; +import dev.salmonllama.fsbot.config.BotConfig; +import org.javacord.api.entity.message.MessageAttachment; +import org.javacord.api.event.message.MessageCreateEvent; +import org.javacord.api.listener.message.MessageCreateListener; + +public class AchievementListener implements MessageCreateListener { + + public void onMessageCreate(MessageCreateEvent event) { + if (!event.getChannel().getIdAsString().equals(BotConfig.ACHIEVEMENT_CHANNEL)) { + return; + } + + if (event.getMessage().getAttachments().stream().noneMatch(MessageAttachment::isImage)) { + return; + } + + event.getMessage().addReaction(EmojiParser.parseToUnicode(":tada:")); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java new file mode 100644 index 0000000..b2964e3 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.listeners; + +import com.rethinkdb.RethinkDB; +import com.rethinkdb.net.Connection; +import com.rethinkdb.net.Cursor; +import com.vdurmont.emoji.EmojiParser; +import okhttp3.*; +import org.javacord.api.entity.message.Message; +import org.javacord.api.entity.message.MessageAttachment; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.event.message.MessageCreateEvent; +import org.javacord.api.listener.message.MessageCreateListener; +import org.json.JSONObject; +import dev.salmonllama.fsbot.config.BotConfig; + +import java.awt.*; +import java.util.List; + +public class ImageListener implements MessageCreateListener { + + final RethinkDB r; + final Connection conn; + + public ImageListener(RethinkDB r, Connection conn) { + this.r = r; + this.conn = conn; + } + + @Override + public void onMessageCreate(MessageCreateEvent event) { + + event.getMessage().getUserAuthor().ifPresent(author -> { + if (author.isBot()) { + return; + } + }); + + Message message = event.getMessage(); + String channel = event.getChannel().getIdAsString(); + String submitter = event.getMessage().getAuthor().getIdAsString(); + + if (message.getAttachments().stream().noneMatch(MessageAttachment::isImage)) { + return; + } + + // If the message contains an image, check if the channel is being listened to for image storage + + String dbTable = null; + + if(r.db("fsbot").table("channels").g("cId").contains(channel).run(conn)) { + Cursor cursor = r.db("fsbot") + .table("channels") + .filter(row -> row.getField("cId").eq(channel)) + .getField("tag") + .run(conn); + + List tags = cursor.toList(); + + for (Object tag : tags) { + dbTable = tag.toString(); + } + } + else { + return; + } + + List attachments = message.getAttachments(); + + for (MessageAttachment attachment : attachments) { + String discordLink = attachment.getUrl().toString(); + String imgurLink = null; + + // Upload the image to imgur + try { + OkHttpClient client = new OkHttpClient(); + + MediaType mediaType = MediaType.parse("multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"); + + RequestBody body = RequestBody.create( + mediaType, + String.format("------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"image\"\r\n\r\n%s\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--", discordLink)); + + Request request = new Request.Builder() + .url("https://api.imgur.com/3/image") + .method("POST", body) + .header("Authorization", BotConfig.IMGUR_ID) + .header("Authorization", BotConfig.IMGUR_BEARER) + .build(); + + Response response = client.newCall(request).execute(); + + if (response.body() == null) { + event.getChannel().sendMessage("Something went wrong!"); + return; + } + + String jsonData = response.body().string(); + imgurLink = new JSONObject(jsonData).getJSONObject("data").getString("link"); + + if (imgurLink == null) { + event.getChannel().sendMessage("Something went wrong!"); + return; + } + + } + catch (Exception e) { + e.printStackTrace(); + } + + r.db("fsbot").table("outfits").insert( + r.hashMap("link", imgurLink) + .with("submitter", submitter) + .with("tag", dbTable) + ).run(conn); + + final String finalLink = imgurLink; + Cursor imgId = r.db("fsbot") + .table("outfits") + .filter(row -> row.getField("link").eq(finalLink)) + .getField("id") + .run(conn); + + String embedId = null; + List imgIds = imgId.toList(); + for (Object id : imgIds) { + embedId = id.toString(); + } + + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Added an entry of tag " + dbTable) + .setColor(Color.GREEN) + .setThumbnail(imgurLink) + .setAuthor("Placeholder") + .setFooter(embedId); + + event.getApi().getUserById(submitter).thenAccept(user -> embed.setAuthor(user.getDiscriminatedName())); + + event.getApi().getChannelById(BotConfig.OUTFIT_LOG).ifPresent(chnl -> { + chnl.asTextChannel().ifPresent(txtchnl -> { + txtchnl.sendMessage(embed).join(); + }); + }); + + message.addReaction(EmojiParser.parseToUnicode(":heartpulse:")); + } + } +} \ No newline at end of file diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java new file mode 100644 index 0000000..e7506a8 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.listeners; + +import dev.salmonllama.fsbot.utilities.database.ServerConfUtility; +import org.javacord.api.DiscordApi; +import org.javacord.api.event.server.member.ServerMemberJoinEvent; +import org.javacord.api.listener.server.member.ServerMemberJoinListener; + +public class NewMemberListener implements ServerMemberJoinListener { + + private DiscordApi api; + + public NewMemberListener(DiscordApi api) { + this.api = api; + } + + public void onServerMemberJoin(ServerMemberJoinEvent event) { + + if (!event.getServer().getIdAsString().equals("340511685024546816")) return; + + ServerConfUtility conf = new ServerConfUtility(event.getServer().getIdAsString()); + String welcomeMsg = conf.getWelcomeMsg(); + String welcomeChannel = conf.getWelcomeChannel(); + + String logMessage = String.format(welcomeMsg, event.getUser().getMentionTag()); + + api.getChannelById(welcomeChannel).ifPresent(chnl -> { + chnl.asServerTextChannel().ifPresent(channel -> { + channel.sendMessage(logMessage); + }); + }); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ReactionDeleteConfirmationListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/ReactionDeleteConfirmationListener.java new file mode 100644 index 0000000..a320213 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ReactionDeleteConfirmationListener.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.listeners; + +import com.vdurmont.emoji.EmojiParser; +import dev.salmonllama.fsbot.config.BotConfig; +import org.javacord.api.entity.channel.Channel; +import org.javacord.api.entity.message.Message; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.user.User; +import org.javacord.api.event.message.reaction.ReactionAddEvent; +import org.javacord.api.listener.message.reaction.ReactionAddListener; +import dev.salmonllama.fsbot.utilities.Outfit; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; +import dev.salmonllama.fsbot.utilities.exceptions.DiscordError; +import dev.salmonllama.fsbot.utilities.exceptions.OutfitNotFoundException; + +import java.awt.*; + +public class ReactionDeleteConfirmationListener implements ReactionAddListener { + + private final User author; + private final Message message; + private final Outfit outfit; + private final DatabaseUtilities db; + + public ReactionDeleteConfirmationListener(User author, Message message, Outfit outfit, DatabaseUtilities db) { + this.author = author; + this.message = message; + this.outfit = outfit; + this.db = db; + } + + public void onReactionAdd(ReactionAddEvent event) { + if (!event.getUser().getIdAsString().equals(author.getIdAsString())) { + return; + } + + if (event.getEmoji().equalsEmoji(EmojiParser.parseToUnicode(":white_check_mark:"))) { + // Delete the message and send confirmation + + String completed = ""; + + try { + completed = db.removeFromDatabase(outfit.getId()); + } + catch(OutfitNotFoundException e) { + event.getChannel().sendMessage(new DiscordError(e.getMessage()).get().addField("Info:", "This message was sent by a reaction listener. **YOU SHOULD NOT BE SEEING THIS!**")); + } + + if (Integer.parseInt(completed) > 0) { + // Successful deletion + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Success!") + .setColor(Color.GREEN) + .setDescription("Outfit deleted successfully"); + + message.removeAllReactions(); + message.edit(embed); + + event.getApi().getChannelById(BotConfig.OUTFIT_LOG).map(Channel::asServerTextChannel).orElseThrow(AssertionError::new).map(channel -> + channel.sendMessage(outfit.generateInfo().setTitle(String.format("Outfit Deleted by %s", event.getUser().getDiscriminatedName())).setColor(Color.RED)) + ); + } + else { + // Deletion failure + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Error!") + .setColor(Color.RED) + .setDescription("An error occurred and the outfit was not deleted. Did you use the correct ID?") + .setFooter(String.format("Bother %s about making these stupid things more useful.", event.getApi().getOwner().thenAccept(User::getDiscriminatedName))); + + message.removeAllReactions(); + message.edit(embed); + } + } + else if (event.getEmoji().equalsEmoji(EmojiParser.parseToUnicode(":octagonal_sign:"))) { + // Cancel deletion and do nothing + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Oops!") + .setColor(Color.GREEN) + .setDescription("Deletion cancelled. No changes were made."); + + message.removeAllReactions(); + message.edit(embed); + } + + event.getApi().removeListener(this); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ReactionRetagConfirmationListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/ReactionRetagConfirmationListener.java new file mode 100644 index 0000000..f1feeba --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ReactionRetagConfirmationListener.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.listeners; + +import com.vdurmont.emoji.EmojiParser; +import dev.salmonllama.fsbot.config.BotConfig; +import org.javacord.api.entity.message.Message; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.user.User; +import org.javacord.api.event.message.reaction.ReactionAddEvent; +import org.javacord.api.listener.message.reaction.ReactionAddListener; +import dev.salmonllama.fsbot.utilities.Outfit; +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; +import dev.salmonllama.fsbot.utilities.exceptions.DiscordError; +import dev.salmonllama.fsbot.utilities.exceptions.OutfitNotFoundException; + +import java.awt.*; + +public class ReactionRetagConfirmationListener implements ReactionAddListener { + + private User author; + private final Message message; + private final Outfit outfit; + private final DatabaseUtilities db; + private final String oldTag; + private final String newTag; + + public ReactionRetagConfirmationListener(User author, Message message, Outfit outfit, DatabaseUtilities db, String oldTag, String newTag) { + this.author = author; + this.message = message; + this.outfit = outfit; + this.db = db; + this.oldTag = oldTag; + this.newTag = newTag; + } + + public void onReactionAdd(ReactionAddEvent event) { + if (!event.getUser().getIdAsString().equals(this.author.getIdAsString())) { + return; + } + + if (event.getEmoji().equalsEmoji(EmojiParser.parseToUnicode(":white_check_mark:"))) { + // retag the image, send a confirmation, or an error if it failed for whatever reason. + String result = ""; + + try { + result = db.changeOutfitTag(outfit.getId(), this.newTag); + } + catch (OutfitNotFoundException e) { + message.delete(); + event.getChannel().sendMessage(new DiscordError(e.getMessage()).get().addField("Info", "This message was generated by a listener thread. YOU SHOULD NOT BE SEEING THIS ERROR!")); + } + + message.removeAllReactions(); + + if (Integer.parseInt(result) > 0) { + // success, send confirmation + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Success") + .setColor(Color.GREEN) + .setDescription("Outfit retagged successfully") + .setFooter("Check the log for more information"); + + message.edit(embed); + + // log message with new tag and old tag + + event.getApi().getChannelById(BotConfig.OUTFIT_LOG).ifPresent(channel -> { + channel.asServerTextChannel().ifPresent(chnl -> { + chnl.sendMessage(outfit.tagChangeEmbed(this.author.getDiscriminatedName(), this.oldTag, this.newTag)); + }); + }); + } + else { + // failure, something went wrong + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Error!") + .setColor(Color.RED) + .setFooter("Big oopsie"); + + event.getApi().getOwner().thenAcceptAsync(user -> { + embed.setDescription(String.format("Something has gone horribly wrong, contact %s", user.getDiscriminatedName())); + }); + + message.edit(embed); + } + } + else if (event.getEmoji().equalsEmoji(EmojiParser.parseToUnicode(":octagonal_sign:"))) { + // Cancel the image retagging. + + message.removeAllReactions(); + + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Operation cancelled!") + .setDescription("No changes made.") + .setColor(Color.GREEN) + .setFooter("boop"); + + message.edit(embed); + } + + event.getApi().removeListener(this); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ReportListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/ReportListener.java new file mode 100644 index 0000000..a1438f9 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ReportListener.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.listeners; + +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.channel.TextChannel; +import org.javacord.api.entity.message.Message; +import org.javacord.api.entity.message.MessageAuthor; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.event.message.MessageCreateEvent; +import org.javacord.api.listener.message.MessageCreateListener; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.utilities.MessageUtilities; + +import java.awt.*; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +public class ReportListener implements MessageCreateListener { + + public void onMessageCreate(MessageCreateEvent event) { + DiscordApi api = event.getApi(); + TextChannel channel = event.getChannel(); + + if (!channel.getIdAsString().equals(BotConfig.REPORT_CHANNEL)) { + return; + } + + Message message = event.getMessage(); + MessageAuthor author = message.getAuthor(); + + if (author.isBotUser()) { + return; + } + + String content = message.getContent(); + + message.delete().join(); + + EmbedBuilder embed = new EmbedBuilder() + .setTitle("User Report") + .setDescription(content) + .setColor(Color.GREEN) + .setFooter("From: " + author.getDiscriminatedName()); + + Optional logChannel = api.getTextChannelById(BotConfig.REPORT_LOG); + if (logChannel.isPresent()) { + logChannel.get().sendMessage(embed); + } + else { + channel.sendMessage("Could not find proper log channel, please contact a staff member.") + .thenAccept(MessageUtilities.deleteAfter(30, TimeUnit.SECONDS)); + + } + + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ServerJoined.java b/src/main/java/dev/salmonllama/fsbot/listeners/ServerJoined.java new file mode 100644 index 0000000..7ad7035 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ServerJoined.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.listeners; + +import dev.salmonllama.fsbot.utilities.database.DatabaseUtilities; +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.event.server.ServerJoinEvent; +import org.javacord.api.listener.server.ServerJoinListener; + +import java.awt.*; + +public class ServerJoined implements ServerJoinListener { + + private DiscordApi api; + private DatabaseUtilities db; + + public ServerJoined(DiscordApi api, DatabaseUtilities db) { + this.api = api; + this.db = db; + } + + public void onServerJoin(ServerJoinEvent event) { + db.newServerProcess(event.getServer()); + + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Server joined") + .setColor(Color.GREEN) + .addInlineField("Server name:", event.getServer().getName()) + .addInlineField("Server Id:", event.getServer().getIdAsString()); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ThumbsListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/ThumbsListener.java new file mode 100644 index 0000000..77ae970 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ThumbsListener.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.listeners; + +import com.vdurmont.emoji.EmojiParser; +import dev.salmonllama.fsbot.config.BotConfig; +import org.javacord.api.event.message.MessageCreateEvent; +import org.javacord.api.listener.message.MessageCreateListener; + +public class ThumbsListener implements MessageCreateListener { + + public void onMessageCreate(MessageCreateEvent event) { + + if (event.getChannel().getIdAsString().equals(BotConfig.ANNOUNCEMENT_CHANNEL)) { + // Announcements + event.getMessage().addReaction(EmojiParser.parseToUnicode(":thumbsup:")); + event.getMessage().addReaction(EmojiParser.parseToUnicode(":thumbsdown:")); + } + else if (event.getChannel().getIdAsString().equals(BotConfig.NEWS_CHANNEL)) { + // Newsfeed + event.getMessage().addReaction(EmojiParser.parseToUnicode(":thumbsup:")); + event.getMessage().addReaction(EmojiParser.parseToUnicode(":thumbsdown:")); + } + else if (event.getChannel().getIdAsString().equals(BotConfig.VOTE_CHANNEL)) { + // Votes + event.getMessage().addReaction(EmojiParser.parseToUnicode(":thumbsup:")); + event.getMessage().addReaction(EmojiParser.parseToUnicode(":thumbsdown:")); + } + + + } + +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/Checks.java b/src/main/java/dev/salmonllama/fsbot/utilities/Checks.java new file mode 100644 index 0000000..0be99cd --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/Checks.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities; + +public class Checks { + + public static boolean checkTag() { + return true; + } + + public static boolean checkId() { + return true; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/ColorRole.java b/src/main/java/dev/salmonllama/fsbot/utilities/ColorRole.java new file mode 100644 index 0000000..2a4bdf9 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/ColorRole.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities; + +import org.javacord.api.entity.message.embed.EmbedBuilder; +import dev.salmonllama.fsbot.utilities.database.RoleColourUtility; + +import java.util.List; +import java.awt.Color; + +public class ColorRole { + public String id; + public String name; + + public ColorRole(String id, String name) { + this.id = id; + this.name = name; + } + + public static EmbedBuilder rolesListEmbed() { + List roles = RoleColourUtility.getAllRoles(); + + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Available ColorRoles") + .setColor(Color.GREEN) + .setFooter("Showing " + roles.size() + " roles"); + + StringBuilder builder = new StringBuilder(); + + roles.forEach(role -> { + builder.append(role.name).append("\n"); + }); + + embed.addField("Roles:", builder.toString()); + + return embed; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/Constants.java b/src/main/java/dev/salmonllama/fsbot/utilities/Constants.java new file mode 100644 index 0000000..0e46308 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/Constants.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities; + +public class Constants { + public static final String BOT_FOLDER = System.getenv("HOME").concat("/.fsbot/"); + + public static final String CONFIG_NAME = "bot.config"; + + public static final String DB_NAME = "fsbot"; + + public static final String OUTFIT_TABLE = "outfits"; + + public static final String SCONF_TABLE = "server_conf"; +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/MessageUtilities.java b/src/main/java/dev/salmonllama/fsbot/utilities/MessageUtilities.java new file mode 100644 index 0000000..7395c20 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/MessageUtilities.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities; + +import org.javacord.api.entity.message.Message; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +public class MessageUtilities { + public static Consumer deleteAfter(long delay, TimeUnit timeUnit) { + return msg -> msg.getApi().getThreadPool().getScheduler().schedule((Runnable) msg::delete, delay, timeUnit); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/Outfit.java b/src/main/java/dev/salmonllama/fsbot/utilities/Outfit.java new file mode 100644 index 0000000..7642bc1 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/Outfit.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities; + +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.message.embed.EmbedBuilder; + +import java.awt.*; + +public class Outfit { + + private String id; + private String tag; + private String submitter; + private String link; + private DiscordApi api; + + public Outfit(String id, String tag, String submitter, String link) { + this.id = id; + this.tag = tag; + this.submitter = submitter; + this.link = link; + } + + public void setId(String id) { this.id = id; } + public String getId() { return this.id; } + + public String getTag() { return this.tag; } + + // public void setTag(String tag) { this.tag = tag; } + // public String getTag() { return this.tag; } + + // public void setSubmitter(String submitter) { this.submitter = submitter; } + // public String getSubmitter() { return this.submitter; } + + // public void setLink(String link) { this.link = link; } + // public String getLink() { return this.link; } + + public EmbedBuilder generateEmbed() { + return new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle(submitter + " | " + tag) + .setImage(this.link) + .setFooter(this.id); + } + + public EmbedBuilder generateInfo() { + return new EmbedBuilder() + .setColor(Color.GREEN) + .setTitle("Outfit Information") + .setThumbnail(this.link) + .addField("Submitter:", this.submitter, true) + .addField("Tag:", this.tag, true) + .addField("Id:", this.id) + .addField("Link:", this.link); + } + + public EmbedBuilder tagChangeEmbed(String changer, String oldTag, String newTag) { + return new EmbedBuilder() + .setColor(Color.YELLOW) + .setTitle(String.format("Tag changed by %s", changer)) + .setThumbnail(this.link) + .addField("Old Tag:", oldTag) + .addField("New Tag:", newTag) + .setFooter(this.id); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/database/DatabaseUtilities.java b/src/main/java/dev/salmonllama/fsbot/utilities/database/DatabaseUtilities.java new file mode 100644 index 0000000..879eac2 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/database/DatabaseUtilities.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.database; + +import com.rethinkdb.RethinkDB; +import com.rethinkdb.gen.ast.Table; +import com.rethinkdb.net.Connection; +import com.rethinkdb.net.Cursor; +import org.javacord.api.DiscordApi; +import dev.salmonllama.fsbot.utilities.Outfit; +import org.javacord.api.entity.server.Server; +import dev.salmonllama.fsbot.utilities.exceptions.OutfitNotFoundException; + +import java.util.*; + +public class DatabaseUtilities { + + private final RethinkDB r; + private final Connection conn; + private final DiscordApi api; + + public DatabaseUtilities(RethinkDB r, Connection conn, DiscordApi api) { + this.r = r; + this.conn = conn; + this.api = api; + } + + private Table getTable(String table) { + if (this.r.db("fsbot").tableList().contains(table).run(this.conn)) { + return this.r.db("fsbot").table(table); + } + else { + return null; + } + } + + private boolean validateId(String id) { + return r.db("fsbot").table("outfits").getField("id").contains(id).run(this.conn); + } + + public boolean tagExists(String tag) { + return r.db("fsbot").table("outfits").getField("tag").distinct().contains(tag).run(this.conn); + } + + public int countTags() { + return this.r.db("fsbot").table("outfits").getField("tag").distinct().count().run(this.conn); + } + + public ArrayList getTags() { + return r.db("fsbot").table("outfits").getField("tag").distinct().run(this.conn); + } + + public Outfit getOutfitFromId(String id) throws OutfitNotFoundException { + if (!this.validateId(id)) throw new OutfitNotFoundException(); + + HashMap sample = this.r.db("fsbot").table("outfits") + .get(id) + .run(this.conn); + + String tag = sample.get("tag").toString(); + String link = sample.get("link").toString(); + String submitterId = sample.get("submitter").toString(); + + String submitterName = api.getUserById(submitterId).join().getDiscriminatedName(); + + return new Outfit(id, tag, submitterName, link); + } + + public String removeFromDatabase(String id) throws OutfitNotFoundException { + if (!this.validateId(id)) throw new OutfitNotFoundException(); + + // Remove outfit return deletion status. 0 = failed, >= 1 = success + HashMap deletion = r.db("fsbot").table("outfits").get(id).delete().run(conn); + + return deletion.get("deleted").toString(); + } + + public Outfit randomOutfit() { + HashMap sample = this.r.db("fsbot").table("outfits") + .sample(1).nth(0) + .run(this.conn); + + String id = sample.get("id").toString(); + String tag = sample.get("tag").toString(); + String link = sample.get("link").toString(); + String submitterId = sample.get("submitter").toString(); + + String submitterName = api.getUserById(submitterId).join().getDiscriminatedName(); + + return new Outfit(id, tag, submitterName, link); + } + + public Outfit randomTaggedOutfit(String targetTag) { + HashMap sample = r.db("fsbot").table("outfits") + .filter(row -> row.getField("tag").eq(targetTag)) + .sample(1).nth(0) + .run(conn); + + String id = String.valueOf(sample.get("id")); + String tag = String.valueOf(sample.get("tag")); + String link = String.valueOf(sample.get("link")); + String submitterId = String.valueOf(sample.get("submitter")); + + String submitterName = api.getUserById(submitterId).join().getDiscriminatedName(); // Try a thenAccept with a thenApply + + return new Outfit(id, tag, submitterName, link); + } + + public String changeOutfitTag(String outfitId, String newTag) throws OutfitNotFoundException { + if (!this.validateId(outfitId)) throw new OutfitNotFoundException(); + + HashMap replacement = this.r.db("fsbot").table("outfits").get(outfitId).update(r.hashMap("tag", newTag)).run(this.conn); + + return replacement.get("replaced").toString(); + } + + public Outfit getOutfitBySubmitter(String userId) { + HashMap sample = r.db("fsbot").table("outfits") + .filter(row -> row.getField("submitter").eq(userId)) + .sample(1).nth(0) + .run(conn); + + String id = String.valueOf(sample.get("id")); + String tag = String.valueOf(sample.get("tag")); + String link = String.valueOf(sample.get("link")); + String submitterId = String.valueOf(sample.get("submitter")); + + String submitterName = api.getUserById(submitterId).join().getDiscriminatedName(); + + return new Outfit(id, tag, submitterName, link); + } + + public long getSubmitterCount(String submitter) { + return r.db("fsbot").table("outfits") + .filter( + row -> row.getField("submitter").eq(submitter) + ) + .count() + .run(conn); + } + + public List getSubmitterIds(String submitter) { + List ids = new ArrayList<>(); + Cursor cursor = r.db("fsbot").table("outfits") + .filter( + row -> row.getField("submitter").eq(submitter) + ) + .getField("id") + .run(conn); + + cursor.forEach(ids::add); + + return ids; + } + + public void updateSubmitter(String submitter, String newSubmitter) { + // Add feature to return update-error? + r.db("fsbot").table("outfits") + .filter(r.hashMap("submitter", submitter)) + .update(r.hashMap("submitter", newSubmitter)) + .run(conn); + } + + public void newServerProcess(Server server) { + + if (this.r.db("fsbot").table("serverConf").contains(server.getIdAsString()).run(this.conn)) { + return; + } + + String serverName = server.getName(); + String serverId = server.getIdAsString(); + String logChannel = "null"; + String giveawayChannel = "null"; + String welcomeChannel = "null"; + String defaultWelcome = "welcome to the server"; + + this.r.db("fsbot").table("serverConf").insert( + this.r.hashMap("id", serverId) + .with("name", serverName) + .with("logChannel", logChannel) + .with("giveawayChannel", giveawayChannel) + .with("welcomeMsg", defaultWelcome) + .with("welcomeChannel", welcomeChannel) + .with("prefix", "~") + ).run(this.conn); + } + + public void tableSetup() { // TODO: Fix this -- invert conditionals, just create the tables. -> if *not* exist then create + // Check for database existence, if not, create + if (r.dbList().contains("fsbot").run(conn)) { +// System.out.println("database 'fsbot' already exists."); + } + else { + r.dbCreate("fsbot").run(conn); + System.out.println("database fsbot did not exist, and has been created"); + } + + // Check for channels table existence, if not, create + if (r.db("fsbot").tableList().contains("channels").run(conn)) { +// System.out.println("table channels already exists"); + } + else { + r.db("fsbot").tableCreate("channels").run(conn); + System.out.println("table channels did not exist, and has been created."); + } + + // Check for serverconf table existence, if not, create + if (r.db("fsbot").tableList().contains("serverConf").run(conn)) { +// System.out.println("table serverConf already exists"); + } + else { + r.db("fsbot").tableCreate("serverConf").run(conn); + System.out.println("table serverConf did not exist, and has been created"); + } + + // Check for permissions table existene, if not, create + if (r.db("fsbot").tableList().contains("permissions").run(conn)) { +// System.out.println("table permissions already exists"); + } + else { + r.db("fsbot").tableCreate("permissions").run(conn); + System.out.println("table permissions did not exist and has been created"); + } + + // Check for outfits table existence, if not, create + if (r.db("fsbot").tableList().contains("outfits").run(conn)) { +// System.out.println("table outfits already exists"); + } + else { + r.db("fsbot").tableCreate("outfits").run(conn); + System.out.println("table outfits did not exist and has been created"); + } + + // Check for colourRoles table existence, if not, create + if (r.db("fsbot").tableList().contains("colourRoles").run(conn)) { +// System.out.println("table colourRoles already exists"); + } + else { + r.db("fsbot").tableCreate("colourRoles").run(conn); + System.out.println("table colourRoles did not exist and has been created"); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/database/RoleColourUtility.java b/src/main/java/dev/salmonllama/fsbot/utilities/database/RoleColourUtility.java new file mode 100644 index 0000000..be86216 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/database/RoleColourUtility.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.database; + +import com.rethinkdb.RethinkDB; +import com.rethinkdb.net.Connection; +import com.rethinkdb.net.Cursor; +import dev.salmonllama.fsbot.utilities.ColorRole; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class RoleColourUtility { + + private static RethinkDB r = RethinkDB.r; + private static Connection conn = r.connection().hostname("localhost").port(28015).connect(); + + public static void addColourRole(String colourName, String roleId) { + r.db("fsbot").table("colourRoles").insert( + r.hashMap("id", roleId) + .with("name", colourName)).run(conn); + } + + public static void deleteColourRole() { + + } + + public static String getColour(String colourName) { + String roleId = null; + + Cursor cursor = r.db("fsbot").table("colourRoles") + .filter(row -> row.getField("name").eq(colourName)) + .getField("id") + .run(conn); + List roleIds = cursor.toList(); + for (Object id : roleIds) { + roleId = id.toString(); + } + + return roleId; + } + + public static List getAllRoles() { + List allRoles = new ArrayList<>(); + + Cursor cursor = r.db("fsbot").table("colourRoles") + .run(conn); + + while (cursor.hasNext()) { + HashMap role = (HashMap) cursor.next(); + + String id = String.valueOf(role.get("id")); + String name = String.valueOf(role.get("name")); + + allRoles.add(new ColorRole(id, name)); + } + + return allRoles; + } + + public static String getAllRoleInfo() { + return r.db("fsbot").table("colourRoles").run(conn); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/database/ServerConfUtility.java b/src/main/java/dev/salmonllama/fsbot/utilities/database/ServerConfUtility.java new file mode 100644 index 0000000..06c2cbf --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/database/ServerConfUtility.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.database; + +import com.rethinkdb.RethinkDB; +import com.rethinkdb.net.Connection; +import com.rethinkdb.net.Cursor; + +import java.util.List; + +public class ServerConfUtility { + + private static final RethinkDB r = RethinkDB.r; + private static final Connection conn = r.connection().hostname("localhost").port(28015).connect(); + + private static String serverId; + + public ServerConfUtility(String sId) { + serverId = sId; + } + + // TODO: Turn server into method args, not class field. + + public String getWelcomeMsg() { + + String welcomeMsg = null; + + Cursor welcomes = r.db("fsbot").table("serverConf") + .filter(row -> row.getField("id").eq(serverId)) + .getField("welcomeMsg") + .run(conn); + List welcomeMsgs = welcomes.toList(); + for (Object msg : welcomeMsgs) { + welcomeMsg = msg.toString(); + } + + return welcomeMsg; + } + + public void setWelcomeMsg(String msg) { + + r.db("fsbot").table("serverConf") + .get(serverId) + .update(r.hashMap("welcomeMsg", msg)) + .run(conn); + } + + public String getWelcomeChannel() { + + String welcomeChannel = null; + + Cursor channels = r.db("fsbot").table("serverConf") + .filter(row -> row.getField("id").eq(serverId)) + .getField("welcomeChannel") + .run(conn); + List welcomeChannels = channels.toList(); + for (Object chnl : welcomeChannels) { + welcomeChannel = chnl.toString(); + } + + return welcomeChannel; + } + + public void setWelcomeChannel(String id) { + + r.db("fsbot").table("serverConf") + .get(serverId) + .update(r.hashMap("welcomeChannel", id)) + .run(conn); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordError.java b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordError.java new file mode 100644 index 0000000..97faa75 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordError.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.exceptions; + +import org.javacord.api.entity.message.embed.EmbedBuilder; + +import java.awt.*; + +public class DiscordError { + + String title = "Error!"; + String message; + String footer = "Contact Salmonllama#5727 if you think this is wrong"; + + public DiscordError(String message) { + this.message = message; + } + + public EmbedBuilder get() { + return new EmbedBuilder().setTitle(this.title).setDescription(this.message).setColor(Color.RED).setFooter(this.footer); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordException.java b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordException.java new file mode 100644 index 0000000..745bce3 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordException.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.exceptions; + +import java.awt.*; + +public class DiscordException { + + private Color color; + private String message; + private String footer; + private String title; + + DiscordException(String title, String message, String footer, Color color) { + this.title = title; + this.message = message; + this.footer = footer; + this.color = color; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordWarning.java b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordWarning.java new file mode 100644 index 0000000..47d1cf2 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/DiscordWarning.java @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.exceptions; + +public class DiscordWarning { +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/OutfitNotFoundException.java b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/OutfitNotFoundException.java new file mode 100644 index 0000000..7253e95 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/OutfitNotFoundException.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.exceptions; + +public class OutfitNotFoundException extends Exception { + + @Override + public String getMessage() { + return "An outfit with that ID was not found"; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/TagNotFoundException.java b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/TagNotFoundException.java new file mode 100644 index 0000000..f455c40 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/exceptions/TagNotFoundException.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.exceptions; + +public class TagNotFoundException extends Exception { + + @Override + public String getMessage() { + return "That tag was not found, check your spelling and try again."; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/warnings/Warning.java b/src/main/java/dev/salmonllama/fsbot/utilities/warnings/Warning.java new file mode 100644 index 0000000..6ca4c39 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/utilities/warnings/Warning.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.utilities.warnings; + +import org.javacord.api.entity.message.embed.EmbedBuilder; + +import java.awt.*; + +public class Warning { + private static Color embedColor = Color.YELLOW; + private static String embedFooter = "Bother Crablet#9999 to add usages to these things"; + private String embedWarning; + + public Warning(String warnMessage) { + this.embedWarning = warnMessage; + } + + public EmbedBuilder sendWarning() { + EmbedBuilder warning = new EmbedBuilder() + .setColor(Color.YELLOW) + .setFooter(embedFooter) + .addField("WARNING", embedWarning); + + return warning; + } +}