diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..22e54e5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM gradle:6.6.1-jdk11 AS build + +ENV ENVIRONMENT=PROD + +COPY --chown=gradle:gradle . /home/gradle/src +WORKDIR /home/gradle/src +RUN gradle build --no-daemon + +FROM openjdk:11-jre-slim + +EXPOSE 8080 + +RUN mkdir /app + +COPY --from=build /home/gradle/src/build/libs/*.jar /app/fashionscape-bot.jar + +ENTRYPOINT ["java","-jar","-Xmx800m","/app/fashionscape-bot.jar"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a50a986 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ + USERNAME=salmonllama + IMAGE=fsbot + TAG := $(shell git describe --tags) + +docker: + echo ${TAG} + docker build -t ${USERNAME}/${IMAGE}:${TAG} . \ No newline at end of file diff --git a/README.md b/README.md index d524100..c767558 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ -#Fashionscape Bot | [![Discord](https://img.shields.io/discord/340511685024546816?color=RED&label=Discord&style=flat-square)](https://discord.gg/Tfvxe22) +#Fashionscape Bot | +[![Discord](https://img.shields.io/discord/340511685024546816?label=Discord)](https://discord.gg/Tfvxe22) +![Java CI with Gradle](https://github.com/Salmonllama/Fashionscape-Bot/workflows/Java%20CI%20with%20Gradle/badge.svg) ---> More info coming soon! \ No newline at end of file +--> More info coming soon! diff --git a/build.gradle b/build.gradle index 03ce3b2..203ec66 100644 --- a/build.gradle +++ b/build.gradle @@ -5,11 +5,14 @@ */ plugins { + id 'org.springframework.boot' version '2.3.3.RELEASE' id 'application' } +apply plugin: 'io.spring.dependency-management' + group 'dev.salmonllama' -version '2.0.0' +version '2.0.1' sourceCompatibility = 11 @@ -27,6 +30,10 @@ dependencies { implementation 'com.vdurmont:emoji-java:4.0.0' implementation 'com.squareup.okhttp3:okhttp:4.4.0' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.boot:spring-boot-starter-web' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation group: 'junit', name: 'junit', version: '4.12' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 1948b90..e708b1c 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d0edec2..12d38de 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,12 +1,5 @@ -# -# 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 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-all.zip diff --git a/gradlew b/gradlew index cccdd3d..4f906e0 100755 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ 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="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -66,6 +82,7 @@ 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 @@ -109,10 +126,11 @@ 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 +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 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 @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +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 index f955316..107acd3 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @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= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ 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% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/privacy.md b/privacy.md index 16c959f..9f88c45 100644 --- a/privacy.md +++ b/privacy.md @@ -1,47 +1,72 @@ # Privacy Policy +**Last updated and effective: July 29, 2020** -To comply with Discord's new Terms of Service, this document exists -to provide an overview of Fashionscape Bot and the information it -collects, and why. +In compliance with Discord’s new Terms of Service regarding Bot/API usage, the FashionScape Bot has created a privacy policy to provide transparency to users regarding the information our bot collects, why it collects this information, and how data is used. A link to this privacy policy can be found by running the `~privacy` command in any Discord server that uses our bot. -This document is also accessible to users within Discord through the -`~privacy` command. +# Stored Data +## Server Data +The FashionScape Bot tracks the “Guild Snowflakes” (also known as “Server ID”) of Discord Servers. -## The data we store -### Guild Data: -Guild Snowflakes (IDs) - Generated by Discord +## User Data +The FashionScape Bot tracks the “User Snowflakes” (also known as “User ID”) of Discord accounts. -### User Data: -User Snowflakes (IDs) - Generated by Discord +## User Content +The FashionScape Bot stores permanent links of user-provided images that have been posted to its designated gallery channels. -### User Content: -Permanent links to user-provided images supplied in gallery channels. -## Why we store it and how we use it -### Guild Data: -Guild IDs are stored so that the bot may use custom prefixes and settings -as a guild's administrators see fit. It is also used to prevent the bot -from joining a guild, should the guild prove to be abusing or misusing -either the bot, or Discord/Jagex Terms of Service. +# Why data is stored, and how we use your data +Data and information are not collected beyond the base information necessary for the FashionScape Bot to perform its necessary functions for users. Such information is outlined below as follows: -### User Data: -User IDs are stored mainly for image attribution, to give proper credit -to users who submit their screenshots to the gallery. +## Guild Data: +- Guild IDs are stored so that the bot may use custom prefixes and settings as a guild's administrators see fit. It is also used to prevent the bot from joining a guild, should the guild prove to be abusing or misusing either the bot, or Discord/Jagex Terms of Service. -User IDs may also be used to prevent a user from utilizing some or all -features of the bot, if the user is proven to be abusing or misusing it. +## User Data: +- User IDs are stored so we can track and give attribution to users who submit screenshots to the FashionScape Bot’s gallery. +- User IDs may also be stored to deny a user from utilizing some or all features of the bot, if we suspect the user to be abusing or misusing our services. -User Content: -Images posted to gallery channels are not stored directly. The bot -first uploads them to a private imgur gallery, and retrieves the link. -This link is then stored in the bot's database as part of the gallery. +## User Content: +- Images posted to gallery channels are not stored directly by the FashionScape Bot. Rather, the bot first uploads them to a private imgur gallery, and retrieves the link. This link is then stored in the bot's database as part of the gallery. +- Text-based content that is sent in the same message as the image being posted. In Discord, this will be the message posted in the “Add A Comment” box in an image upload. [Here](https://media.discordapp.net/attachments/458346171681996815/737738392929829007/meta-describe.png?width=400&height=293) is an example. + - This meta information is only collected so users may add clarifying information to their outfit submissions, such as components used in its creation. In addition, it can be used to credit someone if the outfit was not self-made. -## Accessing and deleting your data -You may request deletion of your submitted content through myself -or another administrator. To do this, either join our discord and -ping one of us, or create an issue on GitHub. +# Accessing and deleting your data +You may request deletion of your data by contacting Salmonllama#5727 or another FashionScapers Administrator. To do this, either join our discord and ping one of us, or create an issue on GitHub. A link to both are provided at the bottom of this privacy policy. -## Questions, Comments, Concerns -Any further questions or concerns may be submitted through the -[Fashionscape Server](https://discord.com/invite/Tfvxe22)'s #report-issues-here channel, or directed to -Salmonllama#5727 or LisaaRS#2604. +# Our Disclosure of Your Information. +We are not in the business of selling your information. We consider this information to be a vital part of our relationship with you. There are, however, certain circumstances in which we may share your information with certain third parties, as set forth below: +- Consent: We may transfer your information with your consent. +- Related Companies: We may also share your information with our Related Companies for purposes consistent with this Privacy Policy. For example, because the FashionScape Bot stores submissions on a private Imgur gallery, that information is sent to Imgur, who are considered to be a “related company.” +- Legal Requirements: We may disclose your information if required to do so by law or in the good faith belief that such action is necessary to (i) comply with a legal obligation, (ii) protect and defend the rights or property of the Company or Related Companies, (iii) protect the personal safety of users of the Services or the public, or (iv) protect against legal liability. + +# Unsolicited Suggestions +You may provide us with ideas for new FashionScape Bot functions, or modifications to existing features, and other unsolicited submissions (collectively, “Unsolicited Suggestions”). All Unsolicited Suggestions shall be deemed to be non-confidential and we shall be free to reproduce, use, disclose, and distribute such unsolicited Information to others without limitation or attribution. + +# Children +Our Services are for users age 13 and over and we do not knowingly collect personal information from children under the age of 13. If you are a parent or guardian of a child under the age of 13 and believe he or she has disclosed personal information to us please contact us through one of our listed contact outlets at the end of this privacy policy. Note: In some countries, the age of digital consent is older than 13. If you are in those countries, you must be at least that age to use the Services. For example, for residents of the EEA, where processing of personal information is based on consent, FashionScape Bot will not knowingly engage in that processing for users under the age of consent established by applicable data protection law. If we learn that we are engaged in that processing with such users, we will halt such processing and will take reasonable measures to promptly remove applicable information from our records. + +# Security +We take reasonable steps to protect the information provided via the Services from loss, misuse, and unauthorized access, disclosure, alteration, or destruction. However, no Internet or email transmission is ever fully secure or error free. In particular, email sent to or from the Services may not be secure. Therefore, you should take special care in deciding what information you send to us via email. Please keep this in mind when disclosing any information via the Internet. + +# Your Data Rights & Choices +- **How can I access the personal data you have about me?** + +If you would like to submit a data access request, please contact us through one of our listed contact outlets at the end of this privacy policy. We will then start the process and provide you a link to access the personal data that FashionScape Bot has on you within 30 days. + +- **How do I correct, update, amend, or delete the personal data you have about me?** + +Please contact us with an explanation of what data subject right you are seeking to exercise. For your protection, we may take steps to verify identity before responding to your request. + +- **How do I object or restrict the manner in which Discord processes my personal data?** +You have a right to ask us to stop using or limit our use of your personal data in certain circumstances—for example, if we have no lawful basis to keep using your data, or if you think your personal data is inaccurate. + +# Changes to this Privacy Policy +We reserve the right to update or modify this Privacy Policy at any time and from time to time without prior notice. Please review this policy periodically, and especially before you provide any information. This Privacy Policy was last updated on the date indicated above. Your continued use of the Services after any changes or revisions to this Privacy Policy shall indicate your agreement with the terms of such revised Privacy Policy. + +# Contact +If you need to contact us for assistance regarding information outlined in this policy, you may contact us through the following methods: + +Salmonllama’s Discord Tag: Salmonllama#5727. +LisaaRS’s Discord Tag: LisaaRS#2604. +FashionScapers Discord Server: [https://discord.com/invite/Tfvxe22](https://discord.com/invite/Tfvxe22). Please use the “#report-issues-here” channel. +Github: [https://github.com/Salmonllama/Fashionscape-Bot/issues/new](https://github.com/Salmonllama/Fashionscape-Bot/issues/new) +Email: salmonllama999@gmail.com diff --git a/src/main/java/dev/salmonllama/fsbot/Main.java b/src/main/java/dev/salmonllama/fsbot/Main.java index 3d93c72..794cb29 100644 --- a/src/main/java/dev/salmonllama/fsbot/Main.java +++ b/src/main/java/dev/salmonllama/fsbot/Main.java @@ -12,15 +12,18 @@ import dev.salmonllama.fsbot.listeners.*; import org.javacord.api.DiscordApiBuilder; import dev.salmonllama.fsbot.utilities.Constants; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; // TODO: auto-switching status messages. // TODO: Add an official Logger --> logging to Discord, not console +@SpringBootApplication public class Main { - public static void main(String[] args) { String configLocation = Constants.BOT_FOLDER.concat(Constants.CONFIG_NAME); - BotConfig.initConfig(configLocation, false); // TODO: Use args to dictate newFiling. Also use args to dictate database setup. + BotConfig.initConfig(configLocation, false); + // TODO: Use args to dictate newFiling. Also use args to dictate database setup. FSDB.init(); @@ -37,8 +40,10 @@ public class Main { 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())); + System.out.printf("Bot invite: %s%n", api.createBotInvite()); + System.out.printf("Logged in as %s%n", api.getYourself().getDiscriminatedName()); }); + + SpringApplication.run(Main.class, args); } } diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java index 3cac897..312cf1d 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java @@ -5,6 +5,7 @@ package dev.salmonllama.fsbot.commands.developer; +import dev.salmonllama.fsbot.Main; import dev.salmonllama.fsbot.database.controllers.OutfitController; import dev.salmonllama.fsbot.guthix.Command; import dev.salmonllama.fsbot.guthix.CommandContext; diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java index 110ea1f..ca11050 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java @@ -5,10 +5,15 @@ package dev.salmonllama.fsbot.commands.general; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.controllers.ColorRoleController; 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.apache.logging.log4j.util.Strings; +import org.javacord.api.entity.server.Server; +import org.javacord.api.entity.user.User; import java.util.ArrayList; import java.util.Arrays; @@ -24,6 +29,43 @@ public class ColorCommand extends Command { @Override public void onCommand(CommandContext ctx) { - ctx.reply("This command is a WIP and will be available soon"); + // The color given will be the args. + // Check if args[0] is reset. If so, remove all color roles. + // Check if the given string is a current color role. + // Remove any color roles that the user has. + // Give the user the color role they specified + ctx.getServer().ifPresentOrElse(server -> { + String[] args = ctx.getArgs(); + if (server.getIdAsString().equals(BotConfig.HOME_SERVER)) { + if (args[0].equals("reset")) { + // Remove all color roles + removeColorRoles(ctx.getUser(), server); + } + + String color = Strings.join(Arrays.asList(args), ' '); + ColorRoleController.get(color).thenAcceptAsync(possibleColorRole -> possibleColorRole.ifPresentOrElse(colorRole -> { + // Remove all color roles + removeColorRoles(ctx.getUser(), server); + // Give the user the one they specified + addColorRole(ctx.getUser(), server, colorRole.getRoleId()); + }, () -> ctx.reply("That color does not exist"))); + } + }, () -> ctx.reply("This command can only be used in the fashionscape server")); + } + + private static void removeColorRoles(User user, Server server) { + ColorRoleController.getAll().thenAcceptAsync( + possibleRoles -> possibleRoles.ifPresent( + colorRoles -> colorRoles.forEach( + colorRole -> server.getRoleById(colorRole.getRoleId()).ifPresent( + role -> user.removeRole(role, "Removed color role") + ) + ) + ) + ); + } + + private static void addColorRole(User user, Server server, long roleId) { + server.getRoleById(roleId).ifPresent(role -> user.addRole(role, "Added color role")); } } diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java index 0f35521..6fa021e 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java @@ -5,10 +5,13 @@ package dev.salmonllama.fsbot.commands.general; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.controllers.ColorRoleController; 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.util.ArrayList; import java.util.Arrays; @@ -24,6 +27,26 @@ public class ColorsCommand extends Command { @Override public void onCommand(CommandContext ctx) { - ctx.reply("This command is a WIP and will be available soon."); + // List available color roles + ctx.getServer().ifPresentOrElse(server -> { + if (server.getIdAsString().equals(BotConfig.HOME_SERVER)) { + ColorRoleController.getAll().thenAcceptAsync( + possibleColorRoles -> possibleColorRoles.ifPresentOrElse(colorRoles -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle("Color roles") + .setFooter(String.format("Found %d roles", colorRoles.size())); + + colorRoles.forEach( + colorRole -> server.getRoleById(colorRole.getRoleId()).ifPresent( + role -> response.addField(colorRole.getColor(), role.getMentionTag(), true) + ) + ); + + ctx.reply(response); + }, () -> ctx.reply("No color roles have been found"))); + } else { + ctx.reply("This command can only be used in the fashionscape server"); + } + }, () -> ctx.reply("This command can only be used in the fashionscape server")); } } diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java index 0e7536f..2863f78 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java @@ -6,14 +6,18 @@ package dev.salmonllama.fsbot.commands.staff; import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.controllers.ColorRoleController; +import dev.salmonllama.fsbot.database.models.ColorRole; 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.permission.Role; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.List; public class AddColorCommand extends Command { @Override public String name() { return "Add Color"; } @@ -25,6 +29,22 @@ public class AddColorCommand extends Command { @Override public void onCommand(CommandContext ctx) { - ctx.reply("This command is a WIP and will be available soon."); + // Command takes only a role mention. + ctx.getServer().ifPresentOrElse(server -> { + if (server.getIdAsString().equals(BotConfig.HOME_SERVER)) { + List roles = ctx.getMessage().getMentionedRoles(); + roles.forEach(role -> { + ColorRole colorRole = new ColorRole.ColorRoleBuilder(role.getId()) + .setColor(role.getName()) + .setServerId(server.getId()) + .build(); + + ColorRoleController.insert(colorRole); + ctx.reply("Added color role:" + colorRole.toString()); + }); + } else { + ctx.reply("This command can only be used in the fashionscape server"); + } + }, () -> ctx.reply("This command can only be used in the fashionscape server")); } } diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java index 0354f51..583c043 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java @@ -5,7 +5,6 @@ package dev.salmonllama.fsbot.commands.staff; -import dev.salmonllama.fsbot.config.BotConfig; import dev.salmonllama.fsbot.database.controllers.OutfitController; import dev.salmonllama.fsbot.guthix.Command; import dev.salmonllama.fsbot.guthix.CommandContext; diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java index 0508bad..3912aad 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java @@ -71,8 +71,9 @@ public class RemoveOutfitCommand extends Command { EmbedBuilder response = new EmbedBuilder() .setTitle("Deletion Successful!") .setDescription(String.format("Outfit %s marked as deleted", outfit.getId())); + + msg.delete(); ctx.reply(response); - // TODO: Log the action in FSBot-Log EmbedBuilder log = new EmbedBuilder() .setTitle("Outfit Marked as Deleted") diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java index 11a72ff..c362e3e 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java @@ -79,7 +79,6 @@ public class RetagCommand extends Command { msg.delete(); ctx.reply(embed); - // TODO: Log the action in FSBot-log EmbedBuilder log = new EmbedBuilder() .setTitle("Outfit Retagged") diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java index 0c2904d..997260d 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java @@ -13,6 +13,7 @@ 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 org.javacord.api.util.logging.ExceptionLogger; import java.util.ArrayList; import java.util.Arrays; @@ -42,61 +43,72 @@ public class WelcomeMessageCommand extends Command { switch (args[0]) { case "get": get(ctx); + break; case "set": // TODO: check for args here - set(ctx, args[1]); + String newMsg = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); + set(ctx, newMsg); + break; + default: + ctx.reply("You used this command incorrectly."); } } private void get(CommandContext ctx) { - ServerConfigController.get(ctx.getServer().get().getIdAsString()).thenAcceptAsync(possibleConf -> { - possibleConf.ifPresentOrElse(conf -> { - EmbedBuilder response = new EmbedBuilder() - .setTitle("Current Welcome Message") - .setDescription(conf.getWelcomeMessage()); + ctx.getServer().ifPresent( // If server is present (not private message) get the server config + server -> ServerConfigController.get(server.getIdAsString()).thenAcceptAsync( + possibleConf -> possibleConf.ifPresentOrElse( // Check for current server config + conf -> ctx.reply(getMsg(conf)), // Fetch and send the current welcome message + () -> ctx.reply(notFound()) // No welcome message exists, sorrynotsorry + ) + )); + } - ctx.reply(response); - }, () -> { - EmbedBuilder response = new EmbedBuilder() - .setTitle("Does not exist!") - .setDescription("No welcome message was found! use `~wmsg set` to set one!"); + private EmbedBuilder getMsg(ServerConfig config) { + return new EmbedBuilder() + .setTitle("Current Welcome Message") + .setDescription(config.getWelcomeMessage()); + } - ctx.reply(response); - }); - }); + private EmbedBuilder notFound() { + return new EmbedBuilder() + .setTitle("Does not exist!") + .setDescription("No welcome message was found! use `~wmsg set` to set one!"); } private void set(CommandContext ctx, String newMsg) { - ServerConfigController.get(ctx.getServer().get().getIdAsString()).thenAcceptAsync(possibleConf -> { - possibleConf.ifPresentOrElse(conf -> { - // Update the config - ServerConfig config = new ServerConfig.ServerConfigBuilder().from(conf) - .setWelcomeMessage(newMsg) - .build(); + ctx.getServer().ifPresent( // If server is present (private msg check) get the server's config + server -> ServerConfigController.get(server.getIdAsString()).thenAcceptAsync( // Check for a current server config + possibleConf -> possibleConf.ifPresentOrElse( + conf -> ctx.reply(updateMsg(conf, newMsg)), // Config exists, update with new welcome message + () -> ctx.reply(setNewMsg(server.getIdAsString(), newMsg))))); // Config does not exist, init and add new welcome message + } - ServerConfigController.update(config); + private EmbedBuilder updateMsg(ServerConfig conf, String newMsg) { + // Updates a welcome message from an already existing server config + ServerConfig config = new ServerConfig.ServerConfigBuilder().from(conf) + .setWelcomeMessage(newMsg) + .build(); - EmbedBuilder response = new EmbedBuilder() - .setTitle("Welcome Message Set") - .addField("New Welcome Message:", config.getWelcomeMessage()); + ServerConfigController.update(config).exceptionally(ExceptionLogger.get()); // TODO: Write a discord Throwable consumer like this - ctx.reply(response); - }, () -> { - // Create a config and set the welcome message - ServerConfig config = new ServerConfig.ServerConfigBuilder() - .setId(ctx.getServer().get().getIdAsString()) - .setPrefix(BotConfig.DEFAULT_PREFIX) - .setWelcomeMessage(newMsg) - .build(); + return new EmbedBuilder() + .setTitle("Welcome Message Set") + .addField("New Welcome Message:", config.getWelcomeMessage()); + } - ServerConfigController.insert(config); + private EmbedBuilder setNewMsg(String serverId, String newMsg) { + // Creates a new server config and adds a welcome message + ServerConfig config = new ServerConfig.ServerConfigBuilder() + .setId(serverId) + .setPrefix(BotConfig.DEFAULT_PREFIX) + .setWelcomeMessage(newMsg) + .build(); - EmbedBuilder response = new EmbedBuilder() - .setTitle("Welcome Message Set!") - .setDescription("server conf has been created") - .addField("New Welcome Message:", newMsg); + ServerConfigController.insert(config); - ctx.reply(response); - }); - }); + return new EmbedBuilder() + .setTitle("Welcome Message Set!") + .setDescription("server conf has been created") + .addField("New Welcome Message:", newMsg); } } diff --git a/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java b/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java index 6911530..f202a66 100644 --- a/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java +++ b/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java @@ -58,7 +58,7 @@ public class BotConfig { public static String OUTFIT_LOG = "outfit log channel"; @ConfigurationOption - public static String BOT_LOG = "bot_log_channel"; + public static String ACTIVITY_LOG = "bot_log_channel"; @ConfigurationOption public static String HYDRIX_ROLE = "hydrix role id here"; diff --git a/src/main/java/dev/salmonllama/fsbot/database/DatabaseProvider.java b/src/main/java/dev/salmonllama/fsbot/database/DatabaseProvider.java index d898bac..d5fe031 100644 --- a/src/main/java/dev/salmonllama/fsbot/database/DatabaseProvider.java +++ b/src/main/java/dev/salmonllama/fsbot/database/DatabaseProvider.java @@ -28,7 +28,8 @@ public class DatabaseProvider { SQLiteConnectionPoolDataSource dataSource = new SQLiteConnectionPoolDataSource(); dataSource.setDatabaseName(DB_NAME); dataSource.setUrl(DB_ADDR); - return dataSource.getConnection(); + c = dataSource.getConnection(); + return c; } catch (SQLException e) { e.printStackTrace(); System.out.println("Could not connect to database, double check config values"); @@ -58,6 +59,8 @@ public class DatabaseProvider { } else if (p instanceof Timestamp) { query.setTimestamp(index, (Timestamp) p); + } else if (p == null) { + query.setNull(index, Types.NULL); } else { throw new UnknownParameterException(p, index); } diff --git a/src/main/java/dev/salmonllama/fsbot/database/FSDB.java b/src/main/java/dev/salmonllama/fsbot/database/FSDB.java index c353589..83f80bd 100644 --- a/src/main/java/dev/salmonllama/fsbot/database/FSDB.java +++ b/src/main/java/dev/salmonllama/fsbot/database/FSDB.java @@ -21,7 +21,7 @@ public class FSDB { return connections.get(key); } - System.out.println(String.format("Specified connection %s has not been set.", key)); + System.out.printf("Specified connection %s has not been set.%n", key); return null; } @@ -39,6 +39,7 @@ public class FSDB { private static void prepareTables() { try { get().query(Outfit.schema()); + get().query(ColorRole.schema()); get().query(GalleryChannel.schema()); get().query(ServerConfig.schema()); get().query(ServerBlacklist.schema()); diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/ColorRoleController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/ColorRoleController.java index 896dd11..e249342 100644 --- a/src/main/java/dev/salmonllama/fsbot/database/controllers/ColorRoleController.java +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/ColorRoleController.java @@ -5,13 +5,15 @@ import dev.salmonllama.fsbot.database.models.ColorRole; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; public class ColorRoleController { // Need insert, get by color, exists by color, exists by role, get by server, count, and delete - public CompletableFuture insert(ColorRole cr) { + public static CompletableFuture insert(ColorRole cr) { return CompletableFuture.runAsync(() -> { try { insertExec(cr); @@ -21,7 +23,7 @@ public class ColorRoleController { }); } - public CompletableFuture exists(String color) { + public static CompletableFuture exists(String color) { return CompletableFuture.supplyAsync(() -> { try { return existsExec(color); @@ -31,7 +33,7 @@ public class ColorRoleController { }); } - public CompletableFuture exists(long roleId) { + public static CompletableFuture exists(long roleId) { return CompletableFuture.supplyAsync(() -> { try { return existsExec(roleId); @@ -41,7 +43,7 @@ public class ColorRoleController { }); } - public CompletableFuture> get(String color) { + public static CompletableFuture> get(String color) { return CompletableFuture.supplyAsync(() -> { try { return getExec(color); @@ -51,7 +53,7 @@ public class ColorRoleController { }); } - public CompletableFuture> get(long roleId) { + public static CompletableFuture> get(long roleId) { return CompletableFuture.supplyAsync(() -> { try { return getExec(roleId); @@ -61,17 +63,17 @@ public class ColorRoleController { }); } - public CompletableFuture count(long serverId) { + public static CompletableFuture>> getAll() { return CompletableFuture.supplyAsync(() -> { try { - return countExec(serverId); + return getAllExec(); } catch (SQLException e) { throw new CompletionException(e); } }); } - public CompletableFuture delete(long roleId) { + public static CompletableFuture delete(long roleId) { return CompletableFuture.runAsync(() -> { try { deleteExec(roleId); @@ -81,7 +83,7 @@ public class ColorRoleController { }); } - public CompletableFuture delete(String color) { + public static CompletableFuture delete(String color) { return CompletableFuture.runAsync(() -> { try { deleteExec(color); @@ -91,7 +93,7 @@ public class ColorRoleController { }); } - private void insertExec(ColorRole cr) throws SQLException { + private static void insertExec(ColorRole cr) throws SQLException { FSDB.get().insert("INSERT INTO color_roles (role_id, server_id, color) VALUES (?, ?, ?)", cr.getRoleId(), cr.getServerId(), @@ -99,7 +101,7 @@ public class ColorRoleController { ); } - private boolean existsExec(String color) throws SQLException { + private static boolean existsExec(String color) throws SQLException { ResultSet rs = FSDB.get().select("SELECT EXISTS(SELECT 1 FROM color_roles WHERE color = ?) AS hmm", color); boolean exists = rs.getBoolean("hmm"); @@ -107,7 +109,7 @@ public class ColorRoleController { return exists; } - private boolean existsExec(long roleId) throws SQLException { + private static boolean existsExec(long roleId) throws SQLException { ResultSet rs = FSDB.get().select("SELECT EXISTS(SELECT 1 FROM color_roles WHERE role_id = ?) AS hmm", roleId); boolean exists = rs.getBoolean("hmm"); @@ -115,7 +117,7 @@ public class ColorRoleController { return exists; } - private Optional getExec(String color) throws SQLException { + private static Optional getExec(String color) throws SQLException { ResultSet rs = FSDB.get().select("SELECT * FROM color_roles WHERE color = ?", color); if (rs.next()) { @@ -128,7 +130,7 @@ public class ColorRoleController { return Optional.empty(); } - private Optional getExec(Long roleId) throws SQLException { + private static Optional getExec(Long roleId) throws SQLException { ResultSet rs = FSDB.get().select("SELECT * FROM color_roles WHERE role_id = ?", roleId); if (rs.next()) { @@ -141,28 +143,31 @@ public class ColorRoleController { return Optional.empty(); } - private int countExec(long serverId) throws SQLException { - ResultSet rs = FSDB.get().select("SELECT COUNT(*) AS count FROM color_roles WHERE server_id = ?", serverId); + private static Optional> getAllExec() throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM color_roles"); - if (rs.next()) { - int count = rs.getInt("count"); + Collection roles = new ArrayList<>(); + while (rs.next()) { + roles.add(mapObject(rs)); FSDB.get().close(rs); - return count; } - FSDB.get().close(rs); - return 0; + if (roles.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(roles); } - private void deleteExec(long roleId) throws SQLException { + private static void deleteExec(long roleId) throws SQLException { FSDB.get().query("DELETE FROM color_roles WHERE role_id = ?", roleId); } - private void deleteExec(String color) throws SQLException { + private static void deleteExec(String color) throws SQLException { FSDB.get().query("DELETE FROM color_roles WHERE color = ?", color); } - private ColorRole mapObject(ResultSet rs) throws SQLException { + private static ColorRole mapObject(ResultSet rs) throws SQLException { return new ColorRole.ColorRoleBuilder(rs.getLong("role_id")) .setServerId(rs.getLong("server_id")) .setColor(rs.getString("color")) diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/OutfitController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/OutfitController.java index b9e4d21..8d6e385 100644 --- a/src/main/java/dev/salmonllama/fsbot/database/controllers/OutfitController.java +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/OutfitController.java @@ -402,7 +402,7 @@ public class OutfitController { .setTag(rs.getString("tag")) .setMeta(rs.getString("meta")) .setCreated(new Timestamp(rs.getLong("created"))) - .setUpdated(new Timestamp((rs.getLong("updated")))) + .setUpdated(new Timestamp(rs.getLong("updated"))) .setDeleted(rs.getBoolean("deleted")) .setFeatured(rs.getBoolean("featured")) .setDisplayCount(rs.getInt("display_count")) diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerConfigController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerConfigController.java index c88a155..e4f4d52 100644 --- a/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerConfigController.java +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerConfigController.java @@ -72,7 +72,7 @@ public class ServerConfigController { } private static void updateExec(ServerConfig config) throws SQLException { - FSDB.get().query("UPDATE server_config SET prefix = ?, welcome_message = ?, welcome_channel = ?, WHERE id = ?", + FSDB.get().query("UPDATE server_config SET prefix = ?, welcome_message = ?, welcome_channel = ? WHERE id = ?", config.getPrefix(), config.getWelcomeMessage(), config.getWelcomeChannel(), diff --git a/src/main/java/dev/salmonllama/fsbot/database/models/ColorRole.java b/src/main/java/dev/salmonllama/fsbot/database/models/ColorRole.java index 39ff347..cd2810a 100644 --- a/src/main/java/dev/salmonllama/fsbot/database/models/ColorRole.java +++ b/src/main/java/dev/salmonllama/fsbot/database/models/ColorRole.java @@ -8,9 +8,9 @@ package dev.salmonllama.fsbot.database.models; import dev.salmonllama.fsbot.database.DatabaseModel; public class ColorRole extends DatabaseModel { - private long roleId; - private long serverId; - private String color; + private final long roleId; + private final long serverId; + private final String color; public ColorRole(ColorRoleBuilder builder) { roleId = builder.roleId; @@ -34,8 +34,13 @@ public class ColorRole extends DatabaseModel { return "CREATE TABLE IF NOT EXISTS color_roles (role_id INTEGER, server_id INTEGER, color TEXT)"; } + @Override + public String toString() { + return String.format("Color Role: {roleId: %d, serverId: %d, color: %s", roleId, serverId, color); + } + public static class ColorRoleBuilder { - private long roleId; + private final long roleId; private long serverId; private String color; diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java index 5a82e6c..021d49d 100644 --- a/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java @@ -11,24 +11,26 @@ import dev.salmonllama.fsbot.database.controllers.GalleryController; import dev.salmonllama.fsbot.database.controllers.OutfitController; import dev.salmonllama.fsbot.database.models.Outfit; import dev.salmonllama.fsbot.endpoints.imgur.ImgurAPIConnection; +import org.javacord.api.entity.channel.ServerTextChannel; 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.javacord.api.util.logging.ExceptionLogger; -import java.sql.Timestamp; +import java.util.UUID; public class ImageListener implements MessageCreateListener { @Override - public void onMessageCreate(MessageCreateEvent event) { // TODO: This needs immediate help + public void onMessageCreate(MessageCreateEvent event) { // Check for valid source -> DONE -> WORKING // Check for gallery channel presence -> DONE -> WORKING // Check for images (attached files and links from approved sources) -> DONE -> WORKING (approved links to be added later) // Upload the image(s) to imgur -> DONE -> WORKING // Store the image in the database -> DONE -> WORKING // Send confirmation && log event -> IN PROGRESS (waiting for logger upgrade) + // Check for production environment to avoid uploading dev images to Imgur -> DONE -> WORKING if (!event.getMessageAuthor().isRegularUser()) { // Ignore anything that is a webhook or a bot message @@ -42,62 +44,89 @@ public class ImageListener implements MessageCreateListener { if (exists) { // Check the message for images if (event.getMessageAttachments().stream().anyMatch(MessageAttachment::isImage)) { - // Upload the image(s) to Imgur, store in database, log the stored images. - ImgurAPIConnection imgur = new ImgurAPIConnection(); + event.getMessageAttachments().stream().filter(MessageAttachment::isImage).forEach(image -> { + // Check the ENVIRONMENT env-var. If PROD -> Upload to imgur and store. If not, just store + // Upload the image(s) to Imgur, store in database, log the stored images. - event.getMessageAttachments() - .stream() - .filter(MessageAttachment::isImage) - .forEach(image -> { - // Upload to Imgur - imgur.uploadImage(image.getUrl().toString()).thenAccept(upload -> { - // Store in the database - Outfit.OutfitBuilder outfitBuilder = new Outfit.OutfitBuilder() - .setId(upload.getId()) - .setMeta(event.getMessageContent()) - .setLink(upload.getLink()) - .setSubmitter(event.getMessageAuthor().getIdAsString()) - .setDeleteHash(upload.getDeleteHash()) - .setCreated(new Timestamp(upload.getDateTime())); - - GalleryController.getTag(channel.getIdAsString()).thenAccept(tag -> { - outfitBuilder.setTag(tag); - Outfit outfit = outfitBuilder.build(); - - OutfitController.insert(outfit).thenAcceptAsync((Void) -> { - // Log the outfit - event.getApi().getServerTextChannelById(BotConfig.OUTFIT_LOG).ifPresentOrElse(chnl -> { - EmbedBuilder response = new EmbedBuilder() - .setTitle("Outfit Added") - .setAuthor(event.getMessageAuthor()) - .setThumbnail(outfit.getLink()) - .setFooter(String.format("%s | %s", outfit.getTag(), outfit.getId())) - .setUrl(outfit.getLink()) - .addField("Uploaded:", outfit.getCreated().toString()); - - if (!outfit.getMeta().equals("")) { - response.addField("Meta:", outfit.getMeta()); - } - - chnl.sendMessage(response); - - // Add the reaction to the original message - GalleryController.getEmoji(channel.getIdAsString()).thenAcceptAsync(emoji -> { - event.getMessage().addReaction(EmojiParser.parseToUnicode(emoji)); - }).exceptionally(ExceptionLogger.get()); - }, () -> { - // Fallback error message to me - event.getApi().getUserById(BotConfig.BOT_OWNER).thenAcceptAsync(user -> { - user.sendMessage("Could not find OUTFIT LOG"); - }); - }); - }); - }); - }).exceptionally(ExceptionLogger.get()); - }); + if (System.getenv("ENVIRONMENT") != null) { + // Upload the image(s) to Imgur, store in database, log the stored images. + System.out.println("PROD environment, uploading"); + uploadAndStore(event, channel, image); + } else { + // Store the image(s) in database, log the stored images. + System.out.println("DEV environment, not uploading"); + store(event, channel, image); + } + }); } } }).exceptionally(ExceptionLogger.get()); }); } -} \ No newline at end of file + + private void uploadAndStore(MessageCreateEvent event, ServerTextChannel channel, MessageAttachment image) { + ImgurAPIConnection imgur = new ImgurAPIConnection(); + + // Upload to Imgur + imgur.uploadImage(image.getUrl().toString()).thenAccept(upload -> { + // Store in the database + Outfit.OutfitBuilder outfitBuilder = new Outfit.OutfitBuilder() + .setId(upload.getId()) + .setMeta(event.getMessageContent()) + .setLink(upload.getLink()) + .setSubmitter(event.getMessageAuthor().getIdAsString()) + .setDeleteHash(upload.getDeleteHash()); + + storeAndLog(event, channel, outfitBuilder); + }).exceptionally(ExceptionLogger.get()); + } + + private void store(MessageCreateEvent event, ServerTextChannel channel, MessageAttachment image) { + // Store in the database + Outfit.OutfitBuilder outfitBuilder = new Outfit.OutfitBuilder() + .setId(UUID.randomUUID().toString()) + .setMeta(event.getMessageContent()) + .setLink("DUMMY-LINK") + .setSubmitter(event.getMessageAuthor().getIdAsString()) + .setDeleteHash("DUMMY-DELETE-HASH"); + + storeAndLog(event, channel, outfitBuilder); + } + + private void storeAndLog(MessageCreateEvent event, ServerTextChannel channel, Outfit.OutfitBuilder outfitBuilder) { + GalleryController.getTag(channel.getIdAsString()).thenAccept(tag -> { + outfitBuilder.setTag(tag); + Outfit outfit = outfitBuilder.build(); + + OutfitController.insert(outfit).thenAcceptAsync((Void) -> { + // Log the outfit + event.getApi().getServerTextChannelById(BotConfig.OUTFIT_LOG).ifPresentOrElse(chnl -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle("Outfit Added") + .setAuthor(event.getMessageAuthor()) + .setThumbnail(outfit.getLink()) + .setFooter(String.format("%s | %s", outfit.getTag(), outfit.getId())) + .setUrl(outfit.getLink()) + .addField("Uploaded:", outfit.getCreated().toString()); + + if (!outfit.getMeta().equals("")) { + response.addField("Meta:", outfit.getMeta()); + } + + chnl.sendMessage(response); + + // Add the reaction to the original message + GalleryController.getEmoji(channel.getIdAsString()).thenAcceptAsync( + emoji -> event.getMessage().addReaction(EmojiParser.parseToUnicode(emoji)) + ).exceptionally(ExceptionLogger.get()); + }, () -> { + // Fallback error message to me + event.getApi().getUserById(BotConfig.BOT_OWNER).thenAcceptAsync( + user -> user.sendMessage("Could not find OUTFIT LOG") + ); + }); + }); + }); + } +} + diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java index 8ea2737..458b439 100644 --- a/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java +++ b/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java @@ -6,6 +6,7 @@ package dev.salmonllama.fsbot.listeners; import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.controllers.ServerConfigController; import org.javacord.api.event.server.member.ServerMemberJoinEvent; import org.javacord.api.listener.server.member.ServerMemberJoinListener; @@ -14,11 +15,14 @@ public class NewMemberListener implements ServerMemberJoinListener { public void onServerMemberJoin(ServerMemberJoinEvent event) { if (!event.getServer().getIdAsString().equals(BotConfig.HOME_SERVER)) { + // Only active in the Fashionscape server, currently. return; } -// String logMessage = String.format(welcomeMsg, event.getUser().getMentionTag()); - - event.getApi().getServerTextChannelById(BotConfig.WELCOME_CHANNEL).ifPresent(channel -> channel.sendMessage("Welcome!")); + // TODO: Use the ServerConfig to retrieve the welcome channel as well. + event.getApi().getServerTextChannelById(BotConfig.WELCOME_CHANNEL).ifPresent( // Get the Welcome Channel + channel -> ServerConfigController.get(event.getServer().getIdAsString()).thenAcceptAsync( // Fetch the server config, if set. + possibleConfig -> possibleConfig.ifPresent( // If config exists + config -> channel.sendMessage(String.format(config.getWelcomeMessage(), event.getUser().getMentionTag()))))); // Send the welcome message } } diff --git a/src/main/java/dev/salmonllama/fsbot/logging/Logger.java b/src/main/java/dev/salmonllama/fsbot/logging/Logger.java index 4d5c5ed..c48d982 100644 --- a/src/main/java/dev/salmonllama/fsbot/logging/Logger.java +++ b/src/main/java/dev/salmonllama/fsbot/logging/Logger.java @@ -18,7 +18,7 @@ public class Logger { private final String OUTFIT_LOG = BotConfig.OUTFIT_LOG; private final String REPORT_LOG = BotConfig.REPORT_LOG; private final String JOIN_LOG = BotConfig.JOIN_LOG; - private final String BOT_LOG = BotConfig.BOT_LOG; + private final String ACTIVITY_LOG = BotConfig.ACTIVITY_LOG; private final String SALMONLLAMA = BotConfig.BOT_OWNER; private EmbedBuilder reportEmbed; @@ -54,7 +54,7 @@ public class Logger { } public void logError(String errorMsg) { - api.getServerTextChannelById(BOT_LOG).ifPresentOrElse(channel -> { + api.getServerTextChannelById(ACTIVITY_LOG).ifPresentOrElse(channel -> { // Log the thing channel.sendMessage("error"); }, () -> {