diff --git a/build.gradle b/build.gradle index 8e42ecf..102779c 100644 --- a/build.gradle +++ b/build.gradle @@ -8,10 +8,10 @@ plugins { id 'application' } -group 'studio.spiderling' +group 'dev.salmonllama' version '1.1.11' -sourceCompatibility = 1.8 +sourceCompatibility = 11 repositories { mavenCentral() @@ -21,13 +21,13 @@ repositories { } dependencies { - + implementation 'org.xerial:sqlite-jdbc:3.30.1' 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 'org.javacord:javacord:3.0.6' implementation 'com.vdurmont:emoji-java:4.0.0' + implementation 'com.squareup.okhttp3:okhttp:4.4.0' - testCompile group: 'junit', name: 'junit', version: '4.12' + testImplementation group: 'junit', name: 'junit', version: '4.12' } mainClassName = 'dev.salmonllama.fsbot.Main' diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/privacy.md b/privacy.md new file mode 100644 index 0000000..16c959f --- /dev/null +++ b/privacy.md @@ -0,0 +1,47 @@ +# Privacy Policy + +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. + +This document is also accessible to users within Discord through the +`~privacy` command. + +## The data we store +### Guild Data: +Guild Snowflakes (IDs) - Generated by Discord + +### User Data: +User Snowflakes (IDs) - Generated by Discord + +### 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. + +### User Data: +User IDs are stored mainly for image attribution, to give proper credit +to users who submit their screenshots to the gallery. + +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 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. + +## 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. + +## 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. diff --git a/src/main/java/dev/salmonllama/fsbot/Main.java b/src/main/java/dev/salmonllama/fsbot/Main.java index cc9251b..3d93c72 100644 --- a/src/main/java/dev/salmonllama/fsbot/Main.java +++ b/src/main/java/dev/salmonllama/fsbot/Main.java @@ -5,16 +5,13 @@ package dev.salmonllama.fsbot; -import com.rethinkdb.RethinkDB; -import com.rethinkdb.net.Connection; import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.FSDB; 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 @@ -23,22 +20,19 @@ public class Main { public static void main(String[] args) { String configLocation = Constants.BOT_FOLDER.concat(Constants.CONFIG_NAME); - BotConfig.initConfig(configLocation); + BotConfig.initConfig(configLocation, false); // TODO: Use args to dictate newFiling. Also use args to dictate database setup. - // 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(); + FSDB.init(); new DiscordApiBuilder().setToken(BotConfig.TOKEN).login().thenAccept(api -> { - DatabaseUtilities db = new DatabaseUtilities(r, conn, api); - db.tableSetup(); - Guthix guthix = new Guthix(api, db); + @SuppressWarnings("unused") + Guthix guthix = new Guthix(api); // Register listeners - api.addMessageCreateListener(new ImageListener(r, conn)); - api.addServerMemberJoinListener(new NewMemberListener(api)); - api.addServerJoinListener(new ServerJoined(api, db)); + api.addMessageCreateListener(new ImageListener()); + api.addServerMemberJoinListener(new NewMemberListener()); + api.addServerJoinListener(new ServerJoined(api)); api.addMessageCreateListener(new ThumbsListener()); api.addMessageCreateListener(new AchievementListener()); api.addMessageCreateListener(new ReportListener()); diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/BlacklistUserCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/BlacklistUserCommand.java new file mode 100644 index 0000000..5a8cfe4 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/BlacklistUserCommand.java @@ -0,0 +1,61 @@ +package dev.salmonllama.fsbot.commands.developer; + +import dev.salmonllama.fsbot.database.controllers.UserBlacklistController; +import dev.salmonllama.fsbot.database.models.UserBlacklist; +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.Arrays; +import java.util.Collection; + +public class BlacklistUserCommand extends Command { + @Override public String name() { return "Blacklist User"; } + @Override public String description() { return "Adds the user to the bot's blacklist, preventing them from using any commands or features"; } + @Override public String usage() { return "blacklistuser "; } + @Override public String category() { return "Developer"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "owner"); } + @Override public Collection aliases() { return Arrays.asList("blacklistuser", "bluser", "sabusr"); } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + + if (args.length < 1) { + // Did it wrong + return; + } + + // If the user is on the blacklist, remove them, otherwise, add them with the reason. + UserBlacklistController.get(args[0]).thenAcceptAsync(possibleBlacklist -> { + possibleBlacklist.ifPresentOrElse(blacklist -> { + // Remove user from the blacklist + UserBlacklistController.delete(blacklist).thenAcceptAsync((Void) -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle("Removed User from Blacklist") + .addField("User ID:", blacklist.getId()) + .addField("Reason for Add", blacklist.getReason()) + .addField("Added:", blacklist.getAdded().toString()); + + ctx.reply(response); + }); + }, () -> { + // Add user to the blacklist, check args + UserBlacklist.UserBlacklistBuilder blBuilder = new UserBlacklist.UserBlacklistBuilder(args[0]); + EmbedBuilder response = new EmbedBuilder().setTitle("Added User to Blacklist").addField("User ID:", args[0]); + + if (args.length > 1) { + String reason = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); + blBuilder.setReason(reason); + response.addField("With reason:", reason); + } + + UserBlacklistController.insert(blBuilder.build()).thenAcceptAsync((Void) -> { + ctx.reply(response); + }); + }); + }); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/CreateGalleryCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/CreateGalleryCommand.java index 1b8c93b..5838bc6 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/developer/CreateGalleryCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/CreateGalleryCommand.java @@ -5,92 +5,82 @@ package dev.salmonllama.fsbot.commands.developer; -import com.rethinkdb.RethinkDB; -import com.rethinkdb.net.Connection; +import com.vdurmont.emoji.EmojiManager; +import com.vdurmont.emoji.EmojiParser; import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.controllers.GalleryController; +import dev.salmonllama.fsbot.database.models.GalleryChannel; 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 org.javacord.api.util.logging.ExceptionLogger; import java.awt.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Optional; 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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "owner"); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("creategallery", "addgallery", "newgallery")); } @Override public void onCommand(CommandContext ctx) { - Optional opServer = ctx.getServer(); - TextChannel channel = ctx.getChannel(); + if (ctx.isPrivateMessage()) { + ctx.reply("This command can only be used in a server!"); // TODO: Stop this. Turn this into a preset no-no embed. + return; + } + if (ctx.getArgs().length < 1) { + ctx.reply("Args are incorrect"); + return; + } + String[] args = ctx.getArgs(); - String targetChannelId = channel.getIdAsString(); - String targetChannelName = channel.asServerChannel().get().getName(); // TODO: un-band-aid this. + // Check if the channel is already a registered gallery channel. + // Create a gallery channel of the current channel. + // Store the gallery channel in the database. - if (!opServer.isPresent()) { - ctx.reply("This command can only be used in a server"); - return; - } - - Server server = opServer.get(); - 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."); + String channelId = ctx.getChannel().getIdAsString(); + if (GalleryController.galleryExists(channelId).join()) { // This is a value that is needed immediately. + ctx.reply("A gallery already exists in this channel, can not create a new one."); 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); + String emoji; + if (args.length == 2) { + emoji = EmojiParser.parseToAliases(args[1]); + } else { + emoji = BotConfig.DEFAULT_REACTION; } - 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); + GalleryChannel.GalleryBuilder galleryBuilder = new GalleryChannel.GalleryBuilder(); + galleryBuilder.setChannelId(channelId); + galleryBuilder.setTag(tag); + galleryBuilder.setEmoji(emoji); + ctx.getServer().ifPresent(server -> { + galleryBuilder.setServerId(server.getIdAsString()); + }); + + GalleryChannel gallery = galleryBuilder.build(); + GalleryController.insert(gallery).thenAcceptAsync((Void) -> { 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("Success", "Gallery has been created:") + .addField("Channel Id:", gallery.getChannelId()) .addField("Tag:", tag) - .addField("End:", String.format("Table \"%s\" created for images in this channel", tag)); - channel.sendMessage(embed); - } + .addField("Emoji:", EmojiParser.parseToUnicode(gallery.getEmoji())) + .addField("End:", String.format("This channel is now being tracked under: %s", tag)); + ctx.reply(embed); + }); } } + diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/DefaultCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/DefaultCommand.java new file mode 100644 index 0000000..ad811a4 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/DefaultCommand.java @@ -0,0 +1,29 @@ +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.entity.message.embed.EmbedBuilder; + +import java.util.Collection; +import java.util.Collections; + +public class DefaultCommand extends Command { + @Override public String name() { return "Default"; } + @Override public String description() { return "The command that gets invoked when the prefix is used, but the command is not recognized"; } + @Override public String usage() { return "you don't use this command"; } + @Override public String category() { return "Invisible"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.OWNER); } + @Override public Collection aliases() { return Collections.singletonList("default"); } + + @Override + public void onCommand(CommandContext ctx) { + EmbedBuilder response = new EmbedBuilder() + .setTitle("Oops!") + .setAuthor(ctx.getApi().getYourself()) + .setDescription("That's my prefix, but I don't know that command! Try using `~help` to see what I can do!"); + + ctx.reply(response); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/EvalCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/EvalCommand.java deleted file mode 100644 index 517e20f..0000000 --- a/src/main/java/dev/salmonllama/fsbot/commands/developer/EvalCommand.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 index 5bc4afc..487e8de 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/developer/InviteCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/InviteCommand.java @@ -21,7 +21,7 @@ public class InviteCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "owner"); } @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("invite", "inv")); } @Override diff --git a/src/main/java/dev/salmonllama/fsbot/commands/developer/PermissionCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/developer/PermissionCommand.java new file mode 100644 index 0000000..676c7d6 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/PermissionCommand.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.developer; + +import dev.salmonllama.fsbot.database.controllers.StaticPermissionController; +import dev.salmonllama.fsbot.database.models.StaticPermission; +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 org.javacord.api.entity.user.User; +import org.javacord.api.util.logging.ExceptionLogger; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class PermissionCommand extends Command { + @Override public String name() { return "Permission"; } + @Override public String description() { return "Manages a user's static permissions"; } + @Override public String usage() { return "permission "; } + @Override public String category() { return "Staff"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.OWNER); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("permission", "permissions", "perm", "perms")); } + + @Override + public void onCommand(CommandContext ctx) { + String[] args = ctx.getArgs(); + + switch(args[0]) { + case "list": + // List all the static permissions + list(ctx); + break; + case "add": + // Add a static permission to the mentioned user, if any + add(ctx); + break; + case "remove": + // Remove a static permission from the mentioned user, if any + remove(ctx); + break; + default: + // You don't know how to use this command LUL + } + } + + private void list(CommandContext ctx) { + if (!ctx.getMessage().getMentionedUsers().isEmpty()) { + User mentionedUser = ctx.getMessage().getMentionedUsers().get(0); + + StaticPermissionController.getByUser(mentionedUser.getIdAsString()).thenAcceptAsync(possiblePerms -> { + possiblePerms.ifPresentOrElse(perms -> { + EmbedBuilder embed = new EmbedBuilder() + .setTitle(String.format("Permissions for %s", mentionedUser.getName())) + .setFooter(String.format("User has %s total static permissions", perms.size())) + .setColor(Color.GREEN); + + perms.forEach(perm -> { + embed.addField(perm.getUserId(), perm.getPermission()); + }); + + ctx.reply(embed); + }, () -> { + EmbedBuilder embed = new EmbedBuilder() + .setTitle("No Permissions Found") + .setDescription(String.format("User %s has no static permissions", mentionedUser.getName())); + + ctx.reply(embed); + }); + }); + } else { + StaticPermissionController.getAll().thenAcceptAsync(possiblePerms -> { + possiblePerms.ifPresentOrElse(perms -> { + EmbedBuilder embed = new EmbedBuilder() + .setTitle("All static permissions") + .setFooter(String.format("Found %s total static permissions", perms.size())) + .setColor(Color.green); + + perms.forEach(perm -> { + embed.addField(perm.getUserId(), perm.getPermission()); + }); + + ctx.reply(embed); + }, () -> { + EmbedBuilder embed = new EmbedBuilder() + .setTitle("No Permissions Found") + .setDescription("No permissions have been added."); + + ctx.reply(embed); + }); + }); + } + } + + private void add(CommandContext ctx) { + if (ctx.getMessage().getMentionedUsers().isEmpty()) { + System.out.println("No mentioned users"); + // If no mentioned users, improper usage + return; + } + + String userId = ctx.getMessage().getMentionedUsers().get(0).getIdAsString(); + + StaticPermission perm = new StaticPermission.StaticPermissionBuilder(userId).setPermission(ctx.getArgs()[2]).build(); + + StaticPermissionController.insert(perm).thenAcceptAsync((Void) -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle("Permissions Added") + .addField("User:", userId) + .addField("Permission:", ctx.getArgs()[2]); + + ctx.reply(response); + }); + } + + private void remove(CommandContext ctx) { // TODO: Remove is not functional + if (ctx.getMessage().getMentionedUsers().isEmpty()) { + // If no mentioned users, improper usage + return; + } + + String userId = ctx.getMessage().getMentionedUsers().get(0).getIdAsString(); + + StaticPermissionController.delete(userId, ctx.getArgs()[2]).thenAcceptAsync((Void) -> { + System.out.println("Permission removed"); + }).exceptionally(ExceptionLogger.get()); + } +} 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 295fe87..3cac897 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/developer/TestCommand.java @@ -5,14 +5,18 @@ package dev.salmonllama.fsbot.commands.developer; +import dev.salmonllama.fsbot.database.controllers.OutfitController; 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.Message; +import org.javacord.api.entity.permission.Role; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.stream.Collectors; public class TestCommand extends Command { @Override public String name() { return "Test"; } @@ -24,6 +28,15 @@ public class TestCommand extends Command { @Override public void onCommand(CommandContext ctx) { - ctx.getChannel().sendMessage("Test Command has been invoked"); + Message msg = ctx.getMessage(); + + Collection roles = msg.getMentionedRoles(); + + roles.stream().map(Role::getIdAsString).collect(Collectors.toList()).forEach(id -> { + ctx.getServer().ifPresent(server -> { + Role r = server.getRoleById(id).orElse(null); + ctx.reply(r.getMentionTag()); + }); + }); } } 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 cfec117..110ea1f 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorCommand.java @@ -5,26 +5,14 @@ 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"; } @@ -36,72 +24,6 @@ public class ColorCommand extends Command { @Override public void onCommand(CommandContext ctx) { - if (!ctx.getServer().isPresent()) { - ctx.reply("This command must be used inside a server."); - return; - } - String[] args = ctx.getArgs(); - DiscordApi api = ctx.getApi(); - Server server = ctx.getServer().get(); - 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()) - ); - } + ctx.reply("This command is a WIP and will be available soon"); } } 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 161c403..0f35521 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/ColorsCommand.java @@ -9,10 +9,6 @@ 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; @@ -28,17 +24,6 @@ public class ColorsCommand extends Command { @Override public void onCommand(CommandContext ctx) { - if (!ctx.getServer().isPresent()) { - ctx.reply("This command must be used in a server."); - return; - } - Server server = ctx.getServer().get(); - TextChannel channel = ctx.getChannel(); - - if (!server.getIdAsString().equals(BotConfig.HOME_SERVER)) { - return; - } - - channel.sendMessage(ColorRole.rolesListEmbed()); + ctx.reply("This command is a WIP and will be available soon."); } } diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/OutfitCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/OutfitCommand.java index b152310..4540ecd 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/general/OutfitCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/OutfitCommand.java @@ -5,85 +5,217 @@ package dev.salmonllama.fsbot.commands.general; +import dev.salmonllama.fsbot.database.controllers.OutfitController; +import dev.salmonllama.fsbot.database.models.Outfit; 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 org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.util.logging.ExceptionLogger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.concurrent.CompletableFuture; public class OutfitCommand extends Command { + private final int MAX_OUTFITS = 5; + private final Collection NON_TAG_ALIASES = new ArrayList<>(Arrays.asList("outfit", "o")); + @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 Collection aliases() { return initAliases(); } @Override public void onCommand(CommandContext ctx) { + // Parse command used for logic path + // if "outfit" -> look for tags. if no tags -> show random + // if not "outfit" -> match the command to existing tags -> look for numbers + String command = ctx.getUsedAlias(); 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; + OutfitController.getDistinctTags().thenAccept(tags -> { + if (tags.contains(command)) { + // args parsing and command logic with tag as caller + handleTagCommand(command, args, ctx); + } else if (NON_TAG_ALIASES.contains(command)) { + // args parsing and command logic with name as caller + handleNameCommand(command, args, ctx); + } + }); + } - 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(); + private void handleTagCommand(String command, String[] args, CommandContext ctx) { + switch (args.length) { + case 0: + // Send one single random outfit of the given tag + OutfitController.findRandomByTag(command).thenAccept(possibleOutfit -> { // TODO: Add an orElse case + possibleOutfit.ifPresent(outfit -> { + ctx.getApi().getUserById(outfit.getSubmitter()).thenAcceptAsync(user -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle(user.getDiscriminatedName()) + .setFooter(String.format("%s | %s", outfit.getTag(), outfit.getId())) + .setImage(outfit.getLink()) + .setUrl(outfit.getLink()); - if (args.length == 2) { - // Send a number of outfits - int iterator = ((Integer.parseInt(args[1]) > MAX_OUTFITS) ? MAX_OUTFITS : Integer.parseInt(args[1])); + if (!outfit.getMeta().equals("")) { + response.setDescription(outfit.getMeta()); + } - for (int i = 0; i < iterator; i++) { - channel.sendMessage(db.getOutfitBySubmitter(userId).generateEmbed()); + ctx.reply(response); + }); + }); + }).exceptionally(ExceptionLogger.get()); + case 1: + // Send the given number of outfits, not to exceed 5 for ratelimit reasons + if (isNumeric(args[0])) { + int num = Math.min(Integer.parseInt(args[0]), MAX_OUTFITS); + + OutfitController.findRandomByTag(command, num).thenAccept(possibleOutfits -> { + possibleOutfits.ifPresent(outfits -> { + outfits.forEach(outfit -> { + ctx.getApi().getUserById(outfit.getSubmitter()).thenAcceptAsync(user -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle(user.getDiscriminatedName()) + .setFooter(String.format("%s | %s", outfit.getTag(), outfit.getId())) + .setImage(outfit.getLink()) + .setUrl(outfit.getLink()); + + if (!outfit.getMeta().equals("")) { + response.setDescription(outfit.getMeta()); + } + + ctx.reply(response); + }); + }); + }); + }); + } else { + ctx.reply("Improper command usage"); // TODO: Logging update reminder } - } - 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"); } } + + private void handleNameCommand(String command, String[] args, CommandContext ctx) { + switch (args.length) { + case 0: + // Send one truly random outfit + OutfitController.findRandom().thenAccept(possibleOutfit -> { + possibleOutfit.ifPresent(outfit -> { + ctx.getApi().getUserById(outfit.getSubmitter()).thenAcceptAsync(user -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle(user.getDiscriminatedName()) + .setFooter(String.format("%s | %s", outfit.getTag(), outfit.getId())) + .setImage(outfit.getLink()) + .setUrl(outfit.getLink()); + + if (!outfit.getMeta().equals("")) { + response.setDescription(outfit.getMeta()); + } + + ctx.reply(response); + }); + }); + }); + case 1: + // Send the given number of outfits, not to exceed 5 for ratelimit reasons + if (isNumeric(args[0])) { + int num = Math.min(Integer.parseInt(args[0]), MAX_OUTFITS); + + OutfitController.findRandom(num).thenAccept(possibleOutfits -> { + possibleOutfits.ifPresent(outfits -> { + outfits.forEach(outfit -> { + ctx.getApi().getUserById(outfit.getSubmitter()).thenAcceptAsync(user -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle(user.getDiscriminatedName()) + .setFooter(String.format("%s | %s", outfit.getTag(), outfit.getId())) + .setImage(outfit.getLink()) + .setUrl(outfit.getLink()); + + if (!outfit.getMeta().equals("")) { + response.setDescription(outfit.getMeta()); + } + + ctx.reply(response); + }); + }); + }); + }); + } else { + // First arg is not a number, send an outfit of the given tag + String tag = args[0]; + OutfitController.findRandomByTag(tag).thenAccept(possibleOutfit -> { + possibleOutfit.ifPresent(outfit -> { + ctx.getApi().getUserById(outfit.getSubmitter()).thenAcceptAsync(user -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle(user.getDiscriminatedName()) + .setFooter(String.format("%s | %s", outfit.getTag(), outfit.getId())) + .setImage(outfit.getLink()) + .setUrl(outfit.getLink()); + + if (!outfit.getMeta().equals("")) { + response.setDescription(outfit.getMeta()); + } + + ctx.reply(response); + }); + }); + }); + } + case 2: + // Send the given number of outfits of the given tag + if (isNumeric(args[1])) { + int num = Math.min(Integer.parseInt(args[1]), MAX_OUTFITS); + + OutfitController.findRandomByTag(args[0], num).thenAccept(possibleOutfits -> { + possibleOutfits.ifPresent(outfits -> { + outfits.forEach(outfit -> { + ctx.getApi().getUserById(outfit.getSubmitter()).thenAcceptAsync(user -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle(user.getDiscriminatedName()) + .setFooter(String.format("%s | %s", outfit.getTag(), outfit.getId())) + .setImage(outfit.getLink()) + .setUrl(outfit.getLink()); + + if (!outfit.getMeta().equals("")) { + response.setDescription(outfit.getMeta()); + } + + ctx.reply(response); + }); + }); + }); + }); + } + } + } + + private Collection initAliases() { + Collection aliases = OutfitController.getDistinctTags().join(); + aliases.addAll(NON_TAG_ALIASES); + return aliases; + } + + private boolean isNumeric(String input) { // If this is needed elsewhere, it will be moved to a public utility + if (input == null) { + return false; + } + + try { + Double.parseDouble(input); + } catch (NumberFormatException e) { + return false; + } + return true; + } + + private CompletableFuture sendOutfit(Outfit outfit) { + // TODO: Replace sending with this + return null; + } } diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/PrivacyCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/PrivacyCommand.java new file mode 100644 index 0000000..253f115 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/PrivacyCommand.java @@ -0,0 +1,36 @@ +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.message.embed.EmbedBuilder; + +import java.util.Collection; +import java.util.Collections; + +public class PrivacyCommand extends Command { + @Override public String name() { return "Privacy"; } + @Override public String description() { return "Directs users to the bot's privacy policy"; } + @Override public String usage() { return "privacy"; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return Collections.singletonList("privacy"); } + + + @Override + public void onCommand(CommandContext ctx) { + String privacyUrl = "https://github.com/Salmonllama/Fashionscape-Bot/blob/database-rewrite/privacy.md"; // TODO: Change this to master + + EmbedBuilder response = new EmbedBuilder() + .setTitle("Click Here to open") + .setUrl(privacyUrl); + + EmbedBuilder response2 = new EmbedBuilder() + .setTitle("Link") + .setDescription(privacyUrl) + .setAuthor(ctx.getApi().getYourself()); + + ctx.reply(response).thenAcceptAsync(msg -> ctx.reply(response2)); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/ShowGalleriesCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/ShowGalleriesCommand.java new file mode 100644 index 0000000..6467fbd --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/ShowGalleriesCommand.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.commands.general; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; + +import org.javacord.api.entity.channel.ServerTextChannel; +import org.javacord.api.entity.message.embed.EmbedBuilder; +import org.javacord.api.entity.server.Server; + +import dev.salmonllama.fsbot.database.controllers.GalleryController; +import dev.salmonllama.fsbot.database.models.GalleryChannel; +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.util.logging.ExceptionLogger; + +public class ShowGalleriesCommand extends Command { + @Override public String name() { return "Show Galleries"; } + @Override public String description() { return "Shows registered gallery channels in the current server"; } + @Override public String usage() { return "showgalleries"; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("showgalleries", "listgalleries")); } + + @Override public void onCommand(CommandContext ctx) { + if (ctx.isPrivateMessage()) { + ctx.reply("This command can only be used within a server"); // TODO: Preset embeds again, yeah + return; + } + + ctx.getServer().ifPresent(server -> { + GalleryController.getGalleriesByServer(server.getIdAsString()) + .exceptionally(ExceptionLogger.get()) + .thenAccept(galleries -> { + ctx.reply(galleryEmbed(galleries, server)); + }); + }); + } + + EmbedBuilder galleryEmbed(Collection galleries, Server server) { // TODO: Base FSBot embed. + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Server Gallery Channels"); + + Collection mentionTags = galleries.stream().map( + galleryChannel -> server.getChannelById( + galleryChannel.getChannelId()).get() // Can call get safely -> The channel is not stored if it is not a valid ServerTextChannel + .asServerTextChannel().get()) // Same as above + .map(ServerTextChannel::getMentionTag).collect(Collectors.toList()); + + Collection tags = galleries.stream().map(GalleryChannel::getTag).collect(Collectors.toList()); + + embed.addField("Channels", String.join("\n", mentionTags), true); + embed.addField("Tags", String.join("\n", tags), true); + + return embed; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/commands/general/SpecificOutfitCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/SpecificOutfitCommand.java deleted file mode 100644 index f80087a..0000000 --- a/src/main/java/dev/salmonllama/fsbot/commands/general/SpecificOutfitCommand.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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/general/StatsCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/general/StatsCommand.java new file mode 100644 index 0000000..c2338f2 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/commands/general/StatsCommand.java @@ -0,0 +1,46 @@ +package dev.salmonllama.fsbot.commands.general; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import org.javacord.api.entity.message.embed.EmbedBuilder; + +import dev.salmonllama.fsbot.database.controllers.OutfitController; +import dev.salmonllama.fsbot.guthix.Command; +import dev.salmonllama.fsbot.guthix.CommandContext; +import dev.salmonllama.fsbot.guthix.CommandPermission; +import dev.salmonllama.fsbot.guthix.PermissionType; + +public class StatsCommand extends Command { + @Override public String name() { return "Stats"; } + @Override public String description() { return "Shows various stats from Fashionscape Bot"; } + @Override public String usage() { return "stats"; } + @Override public String category() { return "General"; } + @Override public CommandPermission permission() { return new CommandPermission(PermissionType.NONE); } + @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("stats")); } + + @Override + public void onCommand(CommandContext ctx) { + // Stats to display: + // Number of users + // Number of servers + // Number of galleries + // Number of non-deleted images + // Number of total images + // CPU and RAM? + int userCount = ctx.getApi().getCachedUsers().size(); // Will these be accurate with sharding? + int serverCount = ctx.getApi().getServers().size(); + + EmbedBuilder embed = new EmbedBuilder(); // TODO: Standard embeds yeah? + embed.setTitle("Stats"); + embed.addField("Users:", String.valueOf(userCount)); + embed.addField("Servers:", String.valueOf(serverCount)); + + OutfitController.countActiveOutfits().thenAccept(count -> embed.addField("Active outfits:", String.valueOf(count))).join(); + OutfitController.countTotalOutfits().thenAccept(count -> embed.addField("Total outifts:", String.valueOf(count))).join(); + OutfitController.countFeaturedOutfits().thenAccept(count -> embed.addField("Featured outfits:", String.valueOf(count))).join(); + + ctx.reply(embed); + } +} \ No newline at end of file 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 436b734..0e7536f 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/AddColorCommand.java @@ -10,14 +10,7 @@ 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; @@ -27,36 +20,11 @@ public class AddColorCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @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]) - ); + ctx.reply("This command is a WIP and will be available soon."); } } diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/EchoCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/EchoCommand.java index 0ee01d5..a2dee70 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/EchoCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/EchoCommand.java @@ -20,7 +20,7 @@ public class EchoCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @Override public Collection aliases() { return new ArrayList<>(Collections.singletonList("echo")); } @Override 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 45c1c0e..0354f51 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetOutfitCommand.java @@ -5,112 +5,36 @@ 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.database.controllers.OutfitController; 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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @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) { + // args is ONLY the ID 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); - } + OutfitController.findById(id).thenAccept(outfitOpt -> { + outfitOpt.ifPresentOrElse( + outfit -> ctx.reply(outfit.toString()), + () -> ctx.reply("Outfit not found, did you get the id right?") + ); + }); } } diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/GetServersCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetServersCommand.java index 938f2a9..54be113 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/GetServersCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/GetServersCommand.java @@ -24,7 +24,7 @@ public class GetServersCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("getservers", "servers")); } @Override diff --git a/src/main/java/dev/salmonllama/fsbot/commands/staff/OutfitInfoCommand.java b/src/main/java/dev/salmonllama/fsbot/commands/staff/OutfitInfoCommand.java index 5b9bd96..607d36c 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/OutfitInfoCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/OutfitInfoCommand.java @@ -6,15 +6,12 @@ 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; 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 org.javacord.api.entity.message.embed.EmbedBuilder; import java.util.ArrayList; import java.util.Arrays; @@ -25,31 +22,36 @@ public class OutfitInfoCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @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())); + ctx.reply("You must supply an outfit ID."); return; } - try { - channel.sendMessage(db.getOutfitFromId(args[0]).generateInfo()); - } - catch (OutfitNotFoundException e) { - channel.sendMessage(new DiscordError(e.getMessage()).get()); - } + String id = args[0]; + OutfitController.findById(id).thenAcceptAsync(possibleOutfit -> { + possibleOutfit.ifPresentOrElse(outfit -> { + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Outfit Info") + .setThumbnail(outfit.getLink()) + .setAuthor(ctx.getApi().getYourself()) + .setUrl(outfit.getLink()) + .setFooter(String.format("Tag: %s", outfit.getTag())) + .addField("Added", outfit.getCreated().toString(), true) + .addField("Updated", outfit.getUpdated().toString(), true) + .addField("Submitted by:", ctx.getApi().getUserById(outfit.getSubmitter()).join().getDiscriminatedName()) + .addField("Deleted", outfit.isDeleted() ? "True" : "False", true) + .addField("Featured", outfit.isFeatured() ? "True" : "False", true); + ctx.reply(embed); + }, () -> { + ctx.reply("Outfit not found"); + }); + }); } } 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 deb3424..0508bad 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/RemoveOutfitCommand.java @@ -7,17 +7,13 @@ package dev.salmonllama.fsbot.commands.staff; import com.vdurmont.emoji.EmojiParser; 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; 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 org.javacord.api.entity.message.embed.EmbedBuilder; import java.util.ArrayList; import java.util.Arrays; @@ -28,38 +24,82 @@ public class RemoveOutfitCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @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(); + long authorId = ctx.getUser().getId(); if (args.length != 1) { - channel.sendMessage("You did that wrong, mate"); + channel.sendMessage("You must supply a valid outfit ID."); return; } // get the outfit, confirm deletion through reaction. - try { - Outfit outfit = db.getOutfitFromId(args[0]); + String outfitId = args[0]; + OutfitController.findById(outfitId).thenAcceptAsync(possibleOutfit -> { + possibleOutfit.ifPresentOrElse(outfit -> { + // Send outfit info, react with selectors, add a listener to the message + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Confirm Outfit Deletion") + .setThumbnail(outfit.getLink()) + .setAuthor(ctx.getApi().getUserById(outfit.getSubmitter()).join()) + .setUrl(outfit.getLink()) + .setFooter(String.format("Tag: %s", outfit.getTag())) + .addField("Added", outfit.getCreated().toString(), true) + .addField("Updated", outfit.getUpdated().toString(), true) + .addField("Submitted by:", ctx.getApi().getUserById(outfit.getSubmitter()).join().getDiscriminatedName()) + .addField("Deleted", outfit.isDeleted() ? "True" : "False", true) + .addField("Featured", outfit.isFeatured() ? "True" : "False", true); - 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()); - } + ctx.reply(embed).thenAcceptAsync(msg -> { + msg.addReaction(EmojiParser.parseToUnicode(":white_check_mark:")); + msg.addReaction(EmojiParser.parseToUnicode(":octagonal_sign:")); + + msg.addReactionAddListener(event -> { + if (event.getUser().getId() != authorId) { + return; + } + + if (event.getEmoji().equalsEmoji(EmojiParser.parseToUnicode(":white_check_mark:"))) { + // Delete the outfit + OutfitController.delete(outfit.getId()); + + EmbedBuilder response = new EmbedBuilder() + .setTitle("Deletion Successful!") + .setDescription(String.format("Outfit %s marked as deleted", outfit.getId())); + ctx.reply(response); + // TODO: Log the action in FSBot-Log + + EmbedBuilder log = new EmbedBuilder() + .setTitle("Outfit Marked as Deleted") + .setThumbnail(outfit.getLink()) + .addField("Deleted By:", ctx.getAuthor().getDiscriminatedName()); + + ctx.getApi().getServerTextChannelById(BotConfig.OUTFIT_LOG).ifPresent(chnl -> { + chnl.sendMessage(log); + }); + + } else if (event.getEmoji().equalsEmoji(EmojiParser.parseToUnicode(":octagonal_sign:"))) { + // Do nothing + EmbedBuilder response = new EmbedBuilder() + .setTitle("Deletion Aborted") + .setDescription(String.format("No modifications were made to %s", outfit.getId())); + + ctx.reply(response); + } + }); + }); + }, () -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle("Outfit not Found") + .setDescription(String.format("ID %s does not exist", outfitId)); + + ctx.reply(response); + }); + }); } } 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 ee9f059..11a72ff 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/RetagCommand.java @@ -7,18 +7,17 @@ package dev.salmonllama.fsbot.commands.staff; import com.vdurmont.emoji.EmojiParser; import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.controllers.OutfitController; +import dev.salmonllama.fsbot.database.models.Outfit; 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 org.javacord.api.entity.message.embed.EmbedBuilder; +import java.awt.*; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -28,37 +27,90 @@ public class RetagCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @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(); + long authorId = ctx.getUser().getId(); if (args.length != 2) { - channel.sendMessage("You did that wrong mate. check the help command."); + channel.sendMessage("Improper usage"); return; } - try { - Outfit outfit = this.db.getOutfitFromId(args[0]); + // Get the outfit, confirm update through reaction + String outfitId = args[0]; + String newTag = args[1]; - 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])); + OutfitController.findById(outfitId).thenAcceptAsync(possibleOutfit -> { + possibleOutfit.ifPresentOrElse(outfit -> { + // Send info, confirmation, and add reaction listener + EmbedBuilder response = new EmbedBuilder() + .setTitle("Confirm Tag Edit") + .setThumbnail(outfit.getLink()) + .setAuthor(ctx.getApi().getUserById(outfit.getSubmitter()).join()) + .setUrl(outfit.getLink()) + .addField("Current Tag:", outfit.getTag()) + .addField("New Tag:", newTag); + + ctx.reply(response).thenAcceptAsync(msg -> { + msg.addReaction(EmojiParser.parseToUnicode(":white_check_mark:")); + msg.addReaction(EmojiParser.parseToUnicode(":octagonal_sign:")); + + msg.addReactionAddListener(event -> { + if (event.getUser().getId() != authorId) { + return; + } + + if (event.getEmoji().equalsEmoji(EmojiParser.parseToUnicode(":white_check_mark:"))) { + // Update the outfit + Outfit newOutfit = new Outfit.OutfitBuilder(outfit) + .setTag(newTag) + .setUpdated(new Timestamp(System.currentTimeMillis())) + .build(); + + OutfitController.update(newOutfit).thenAcceptAsync((Void) -> { + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Outfit retagged successfully!") + .setDescription(String.format("Outfit %s will now display as %s", newOutfit.getId(), newOutfit.getTag())); + + msg.delete(); + ctx.reply(embed); + // TODO: Log the action in FSBot-log + + EmbedBuilder log = new EmbedBuilder() + .setTitle("Outfit Retagged") + .setThumbnail(outfit.getLink()) + .addField("New tag:", newTag); + + ctx.getApi().getServerTextChannelById(BotConfig.OUTFIT_LOG).ifPresent(chnl -> { + chnl.sendMessage(log); + }); + }); + + } else if (event.getEmoji().equalsEmoji(EmojiParser.parseToUnicode(":octagonal_sign:"))) { + // Do nothing + msg.delete(); + EmbedBuilder embed = new EmbedBuilder() + .setTitle("Update Cancelled") + .setDescription("No modifications were made"); + + ctx.reply(embed); + } + }); + }); + }, () -> { + // Err, outfit not found + EmbedBuilder response = new EmbedBuilder() + .setTitle("Error occurred") + .setDescription("That ID was not found in the database") + .setColor(Color.RED); + + ctx.reply(response); }); - } - 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 index 8ab296c..785371a 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/SetStatusCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/SetStatusCommand.java @@ -23,7 +23,7 @@ public class SetStatusCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("setstatus", "status")); } @Override 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 c4b343e..0c2904d 100644 --- a/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java +++ b/src/main/java/dev/salmonllama/fsbot/commands/staff/WelcomeMessageCommand.java @@ -6,17 +6,14 @@ package dev.salmonllama.fsbot.commands.staff; import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.controllers.ServerConfigController; +import dev.salmonllama.fsbot.database.models.ServerConfig; 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; @@ -26,89 +23,80 @@ public class WelcomeMessageCommand extends Command { @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 CommandPermission permission() { return new CommandPermission(PermissionType.STATIC, "staff"); } @Override public Collection aliases() { return new ArrayList<>(Arrays.asList("welcomemessage", "wmsg")); } @Override public void onCommand(CommandContext ctx) { - if (!ctx.getServer().isPresent()) { - ctx.reply("You must use this command in a server"); + if (ctx.isPrivateMessage()) { + ctx.reply("This command can only be used within a server"); return; } + + if (ctx.getArgs().length < 1) { + ctx.reply("You need to supply arguments for this command"); + return; + } + String[] args = ctx.getArgs(); - TextChannel channel = ctx.getChannel(); - Server server = ctx.getServer().get(); - - 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; + case "get": + get(ctx); + case "set": // TODO: check for args here + set(ctx, args[1]); } } - private EmbedBuilder fetchWelcomeMsg(Server server) { + 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()); - ServerConfUtility conf = new ServerConfUtility(server.getIdAsString()); - String msg = conf.getWelcomeMsg(); + ctx.reply(response); + }, () -> { + EmbedBuilder response = new EmbedBuilder() + .setTitle("Does not exist!") + .setDescription("No welcome message was found! use `~wmsg set` to set one!"); - return new EmbedBuilder() - .setColor(Color.GREEN) - .setTitle("Current welcome message:") - .setDescription(msg); + ctx.reply(response); + }); + }); } - private EmbedBuilder updateWelcomeMsg(String msg, Server server) { + 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(); - ServerConfUtility conf = new ServerConfUtility(server.getIdAsString()); - conf.setWelcomeMsg(msg); + ServerConfigController.update(config); - return new EmbedBuilder() - .setColor(Color.GREEN) - .setTitle("Welcome message updated") - .addField("New welcome message:", msg); - } + EmbedBuilder response = new EmbedBuilder() + .setTitle("Welcome Message Set") + .addField("New Welcome Message:", config.getWelcomeMessage()); - private EmbedBuilder fetchWelcomeChannel(Server server) { + 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(); - ServerConfUtility conf = new ServerConfUtility(server.getIdAsString()); - String welcomeChannel = conf.getWelcomeChannel(); + ServerConfigController.insert(config); - return new EmbedBuilder() - .setColor(Color.GREEN) - .setTitle("Current welcome channel:") - .setDescription(welcomeChannel); - } + EmbedBuilder response = new EmbedBuilder() + .setTitle("Welcome Message Set!") + .setDescription("server conf has been created") + .addField("New Welcome Message:", newMsg); - 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); + ctx.reply(response); + }); + }); } } diff --git a/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java b/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java index 180e55f..6911530 100644 --- a/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java +++ b/src/main/java/dev/salmonllama/fsbot/config/BotConfig.java @@ -3,6 +3,7 @@ * All rights reserved. */ +// Shoutout to Kaaz (again) for a kickass config service: https://github.com/Kaaz/ConfigurationBuilder package dev.salmonllama.fsbot.config; import com.kaaz.configuration.ConfigurationBuilder; @@ -15,10 +16,10 @@ public class BotConfig { public static String TOKEN = "token-goes-here"; @ConfigurationOption - public static String DB_HOST = "localhost"; + public static String DB_ADDR = "fsbot.db"; @ConfigurationOption - public static int DB_PORT = 28015; + public static String DB_NAME = "fsbot"; @ConfigurationOption public static String DEFAULT_PREFIX = "~"; @@ -44,6 +45,12 @@ public class BotConfig { @ConfigurationOption public static String VOTE_CHANNEL = "vote channel here"; + @ConfigurationOption + public static String WELCOME_CHANNEL = "welcome channel here"; + + @ConfigurationOption + public static String JOIN_LOG = "join log channel"; + @ConfigurationOption public static String REPORT_LOG = "report_log_channel"; @@ -63,11 +70,14 @@ public class BotConfig { public static String IMGUR_BEARER = "imgur bearer here"; @ConfigurationOption - public static String HOME_SERVER = "340511685024546816"; + public static String DEFAULT_REACTION = ":heartpulse:"; - public static void initConfig(String filePath) { + @ConfigurationOption + public static String HOME_SERVER = "Home server here"; + + public static void initConfig(String filePath, boolean cleanfile) { try { - new ConfigurationBuilder(BotConfig.class, new File(filePath)).build(false); + new ConfigurationBuilder(BotConfig.class, new File(filePath)).build(cleanfile); } catch (Exception e) { e.printStackTrace(); System.exit(1); diff --git a/src/main/java/dev/salmonllama/fsbot/database/DatabaseModel.java b/src/main/java/dev/salmonllama/fsbot/database/DatabaseModel.java new file mode 100644 index 0000000..41f9ddd --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/DatabaseModel.java @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database; + +public class DatabaseModel { +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/DatabaseProvider.java b/src/main/java/dev/salmonllama/fsbot/database/DatabaseProvider.java new file mode 100644 index 0000000..d898bac --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/DatabaseProvider.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +// Heavily inspired by Kaaz's Emily database connection: https://github.com/Kaaz/DiscordBot/tree/master/src/main/java/emily/db +package dev.salmonllama.fsbot.database; + +import dev.salmonllama.fsbot.exceptions.UnknownParameterException; +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.utilities.Constants; +import org.sqlite.javax.SQLiteConnectionPoolDataSource; + +import java.sql.*; + +public class DatabaseProvider { + private final String DB_ADDR; + private final String DB_NAME; + private Connection c; + + public DatabaseProvider(String dbName) { + DB_NAME = dbName; + DB_ADDR = "jdbc:sqlite:".concat(Constants.BOT_FOLDER).concat(BotConfig.DB_ADDR); + } + + private Connection createConnection() { + try { + SQLiteConnectionPoolDataSource dataSource = new SQLiteConnectionPoolDataSource(); + dataSource.setDatabaseName(DB_NAME); + dataSource.setUrl(DB_ADDR); + return dataSource.getConnection(); + } catch (SQLException e) { + e.printStackTrace(); + System.out.println("Could not connect to database, double check config values"); + System.exit(1); + } + return null; + } + + public Connection getConnection() { + if (c == null) { + return createConnection(); + } + return c; + } + + private void resolveParameters(PreparedStatement query, Object... params) throws SQLException { + int index = 1; + for (Object p : params) { + if (p instanceof String) { + query.setString(index, (String) p); + } + else if (p instanceof Integer) { + query.setInt(index, (int) p); + } + else if (p instanceof Boolean) { + query.setBoolean(index, (boolean) p); + } + else if (p instanceof Timestamp) { + query.setTimestamp(index, (Timestamp) p); + } else { + throw new UnknownParameterException(p, index); + } + index++; + } + } + + public int query(String sql) throws SQLException { + try (Statement stmt = getConnection().createStatement()) { + return stmt.executeUpdate(sql); + } + } + + public int query(String sql, Object... params) throws SQLException { + try (PreparedStatement stmt = getConnection().prepareStatement(sql)) { + resolveParameters(stmt, params); + return stmt.executeUpdate(); + } + } + + public int insert(String sql, Object... params) throws SQLException { + try ( + PreparedStatement query = getConnection().prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + ResultSet rs = query.getGeneratedKeys() + ) { + resolveParameters(query, params); + query.executeUpdate(); + + if (rs.next()) { + return rs.getInt(1); + } + + return -1; + } + } + + public ResultSet select(String sql, Object... params) throws SQLException { + PreparedStatement query; + query = getConnection().prepareStatement(sql); + resolveParameters(query, params); + return query.executeQuery(); + } + + public void close(ResultSet rs) throws SQLException { + rs.getStatement().close(); + rs.close(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/FSDB.java b/src/main/java/dev/salmonllama/fsbot/database/FSDB.java new file mode 100644 index 0000000..c353589 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/FSDB.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +// Heavily inspired by Kaaz's Emily database connection: https://github.com/Kaaz/DiscordBot/tree/master/src/main/java/emily/db +package dev.salmonllama.fsbot.database; + +import dev.salmonllama.fsbot.config.BotConfig; +import dev.salmonllama.fsbot.database.models.*; + +import java.sql.SQLException; +import java.util.HashMap; + +public class FSDB { + private static final String DEFAULT_CONNECTION = "fsbot"; + private static final HashMap connections = new HashMap<>(); + + public static DatabaseProvider get(String key) { + if (connections.containsKey(key)) { + return connections.get(key); + } + + System.out.println(String.format("Specified connection %s has not been set.", key)); + return null; + } + + public static DatabaseProvider get() { + return connections.get(DEFAULT_CONNECTION); + } + + public static void init() { + connections.clear(); + connections.put(DEFAULT_CONNECTION, new DatabaseProvider(BotConfig.DB_NAME)); + + prepareTables(); + } + + private static void prepareTables() { + try { + get().query(Outfit.schema()); + get().query(GalleryChannel.schema()); + get().query(ServerConfig.schema()); + get().query(ServerBlacklist.schema()); + get().query(UserBlacklist.schema()); + get().query(StaticPermission.schema()); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/ColorRoleController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/ColorRoleController.java new file mode 100644 index 0000000..896dd11 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/ColorRoleController.java @@ -0,0 +1,171 @@ +package dev.salmonllama.fsbot.database.controllers; + +import dev.salmonllama.fsbot.database.FSDB; +import dev.salmonllama.fsbot.database.models.ColorRole; + +import java.sql.ResultSet; +import java.sql.SQLException; +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) { + return CompletableFuture.runAsync(() -> { + try { + insertExec(cr); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public CompletableFuture exists(String color) { + return CompletableFuture.supplyAsync(() -> { + try { + return existsExec(color); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public CompletableFuture exists(long roleId) { + return CompletableFuture.supplyAsync(() -> { + try { + return existsExec(roleId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public CompletableFuture> get(String color) { + return CompletableFuture.supplyAsync(() -> { + try { + return getExec(color); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public CompletableFuture> get(long roleId) { + return CompletableFuture.supplyAsync(() -> { + try { + return getExec(roleId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public CompletableFuture count(long serverId) { + return CompletableFuture.supplyAsync(() -> { + try { + return countExec(serverId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public CompletableFuture delete(long roleId) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(roleId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public CompletableFuture delete(String color) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(color); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + private void insertExec(ColorRole cr) throws SQLException { + FSDB.get().insert("INSERT INTO color_roles (role_id, server_id, color) VALUES (?, ?, ?)", + cr.getRoleId(), + cr.getServerId(), + cr.getColor() + ); + } + + private 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"); + + FSDB.get().close(rs); + return exists; + } + + private 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"); + + FSDB.get().close(rs); + return exists; + } + + private Optional getExec(String color) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM color_roles WHERE color = ?", color); + + if (rs.next()) { + ColorRole colorRole = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(colorRole); + } + + FSDB.get().close(rs); + return Optional.empty(); + } + + private Optional getExec(Long roleId) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM color_roles WHERE role_id = ?", roleId); + + if (rs.next()) { + ColorRole colorRole = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(colorRole); + } + + FSDB.get().close(rs); + 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); + + if (rs.next()) { + int count = rs.getInt("count"); + FSDB.get().close(rs); + return count; + } + + FSDB.get().close(rs); + return 0; + } + + private void deleteExec(long roleId) throws SQLException { + FSDB.get().query("DELETE FROM color_roles WHERE role_id = ?", roleId); + } + + private void deleteExec(String color) throws SQLException { + FSDB.get().query("DELETE FROM color_roles WHERE color = ?", color); + } + + private ColorRole mapObject(ResultSet rs) throws SQLException { + return new ColorRole.ColorRoleBuilder(rs.getLong("role_id")) + .setServerId(rs.getLong("server_id")) + .setColor(rs.getString("color")) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/GalleryController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/GalleryController.java new file mode 100644 index 0000000..943a066 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/GalleryController.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.controllers; + +import dev.salmonllama.fsbot.database.FSDB; +import dev.salmonllama.fsbot.database.models.GalleryChannel; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +public class GalleryController { + public static CompletableFuture insert(GalleryChannel gallery) { + return CompletableFuture.runAsync(() -> { + try { + insertExec(gallery); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> getGalleriesByServer(String serverId) { + return CompletableFuture.supplyAsync(() -> { + try { + return getGalleriesByServerExec(serverId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture galleryExists(String channelId) { + return CompletableFuture.supplyAsync(() -> { + try { + return galleryExistsExec(channelId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture getTag(String channelId) { + return CompletableFuture.supplyAsync(() -> { + try { + return getTagExec(channelId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture getEmoji(String channelId) { + return CompletableFuture.supplyAsync(() -> { + try { + return getEmojiExec(channelId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + private static void insertExec(GalleryChannel gallery) throws SQLException { + FSDB.get().insert("INSERT INTO galleries(server_id, channel_id, tag, emoji)" + + "VALUES(?, ?, ?, ?)", + gallery.getServerId(), + gallery.getChannelId(), + gallery.getTag(), + gallery.getEmoji() + ); + } + + private static Collection getGalleriesByServerExec(String serverId) throws SQLException { // TODO: What if the server has no galleries eh? + ResultSet rs = FSDB.get().select("SELECT * FROM galleries WHERE server_id = ?", serverId); + + Collection galleries = new ArrayList<>(); + while (rs.next()) { + galleries.add(mapObject(rs)); + } + + FSDB.get().close(rs); + return galleries; + } + + private static boolean galleryExistsExec(String channelId) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT EXISTS(SELECT 1 FROM galleries WHERE channel_id = ?) AS hmm", channelId); + boolean exists = rs.getBoolean("hmm"); + + FSDB.get().close(rs); + return exists; + } + + private static String getTagExec(String channelId) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM galleries WHERE channel_id = ?", channelId); + String tag = rs.getString("tag"); + + FSDB.get().close(rs); + return tag; + } + + private static String getEmojiExec(String channelId) throws SQLException { + // Does not need to be an optional. CreateGalleryCommand populates it automatically with the default. + ResultSet rs = FSDB.get().select("SELECT * FROM galleries WHERE channel_id = ?", channelId); + String emoji = rs.getString("emoji"); + + FSDB.get().close(rs); + return emoji; + } + + private static GalleryChannel mapObject(ResultSet rs) throws SQLException { // TODO: Builder this + return new GalleryChannel.GalleryBuilder() + .setServerId(rs.getString("server_id")) + .setChannelId(rs.getString("channel_id")) + .setTag(rs.getString("tag")) + .setEmoji(rs.getString("emoji")) + .build(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/OutfitController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/OutfitController.java new file mode 100644 index 0000000..b9e4d21 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/OutfitController.java @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.controllers; + +import dev.salmonllama.fsbot.database.FSDB; +import dev.salmonllama.fsbot.database.models.Outfit; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +public class OutfitController { + // There is no delete method. 'Deletions' should be executed as an update to the deleted flag. + public static CompletableFuture insert(Outfit outfit) { + return CompletableFuture.runAsync(() -> { + try { + insertExec(outfit); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> findById(String id) { + return CompletableFuture.supplyAsync(() -> { + try { + return findByIdExec(id); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> findRandom() { + return CompletableFuture.supplyAsync(() -> { + try { + return findRandomExec(); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture>> findRandom(int amount) { + return CompletableFuture.supplyAsync(() -> { + try { + return findRandomExec(amount); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> findRandomByTag(String tag) { + return CompletableFuture.supplyAsync(() -> { + try { + return findRandomByTagExec(tag); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture>> findRandomByTag(String tag, int amount) { + return CompletableFuture.supplyAsync(() -> { + try { + return findRandomByTagExec(tag, amount); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> findRandomBySubmitter(String submitterId) { + return CompletableFuture.supplyAsync(() -> { + try { + return findRandomBySubmitterExec(submitterId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture>> findRandomBySubmitter(String submitterId, int amount) { + return CompletableFuture.supplyAsync(() -> { + try { + return findRandomBySubmitterExec(submitterId, amount); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture countTotalOutfits() { + return CompletableFuture.supplyAsync(() -> { + try { + return countTotalOutfitsExec(); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture countDeletedOutfits() { + return CompletableFuture.supplyAsync(() -> { + try { + return countDeletedOutfitsExec(); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture countActiveOutfits() { + return CompletableFuture.supplyAsync(() -> { + try { + return countActiveOutfitsExec(); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture countFeaturedOutfits() { + return CompletableFuture.supplyAsync(() -> { + try { + return countFeaturedOutfitsExec(); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture countOutfits(boolean deleted, boolean featured) { + return CompletableFuture.supplyAsync(() -> { + try { + return countOutfitsExec(deleted, featured); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture countOutfitsBySubmitter(String submitterId) { + return CompletableFuture.supplyAsync(() -> { + try { + return countOutfitsBySubmitterExec(submitterId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> getDistinctTags() { + return CompletableFuture.supplyAsync(() -> { + try { + return getDistinctTagsExec(); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture update(Outfit outfit) { + return CompletableFuture.runAsync(() -> { + try { + updateExec(outfit); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture delete(String id) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(id); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture delete(Outfit outfit) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(outfit.getId()); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + private static void insertExec(Outfit outfit) throws SQLException { + if (outfit.getCreated() == null) { + outfit.setCreated(new Timestamp(System.currentTimeMillis())); + } + + if (outfit.getUpdated() == null) { + outfit.setUpdated(new Timestamp(System.currentTimeMillis())); + } + + FSDB.get().insert( + "INSERT INTO " + + "outfits('id', 'link', 'submitter', 'tag', 'meta', 'created', 'updated', 'deleted', 'featured', 'display_count', 'delete_hash') " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + outfit.getId(), + outfit.getLink(), + outfit.getSubmitter(), + outfit.getTag(), + outfit.getMeta(), + outfit.getCreated(), + outfit.getUpdated(), + outfit.isDeleted(), + outfit.isFeatured(), + outfit.getDisplayCount(), + outfit.getDeleteHash() + ); + } + + private static Optional findByIdExec(String id) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM outfits WHERE id = ?", id); + + if (rs.next()) { + Outfit outfit = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(outfit); + } + + FSDB.get().close(rs); + return Optional.empty(); + } + + private static Optional findRandomExec() throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM outfits WHERE deleted = 0 ORDER BY random() LIMIT 1"); + + if (rs.next()) { + Outfit outfit = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(outfit); + } + + FSDB.get().close(rs); + return Optional.empty(); + } + + private static Optional> findRandomExec(int amount) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM outfits WHERE deleted = 0 ORDER BY random() LIMIT ?", amount); + + return extractMultiple(rs); + } + + private static Optional findRandomByTagExec(String tag) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM outfits WHERE tag = ? AND deleted = 0 ORDER BY random() LIMIT 1", tag); + + if (rs.next()) { + Outfit outfit = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(outfit); + } + + FSDB.get().close(rs); + return Optional.empty(); + } + + private static Optional> findRandomByTagExec(String tag, int amount) throws SQLException { // Still has to be an optional, the tag may not exist. It is user-supplied. + ResultSet rs = FSDB.get().select("SELECT * FROM outfits WHERE tag = ? AND deleted = 0 ORDER BY random() LIMIT ?", tag, amount); + + return extractMultiple(rs); + } + + private static Optional findRandomBySubmitterExec(String submitterId) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM outfits WHERE submitter = ? AND deleted = 0 ORDER BY random() LIMIT 1", submitterId); + + if (rs.next()) { + Outfit outfit = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(outfit); + } + + FSDB.get().close(rs); + return Optional.empty(); + } + + private static Optional> findRandomBySubmitterExec(String submitterId, int amount) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM outfits WHERE submitter = ? AND deleted = 0 ORDER BY random() LIMIT ?", submitterId, amount); + + return extractMultiple(rs); + } + + private static int countTotalOutfitsExec() throws SQLException { + ResultSet rs = FSDB.get().select("SELECT COUNT(*) AS count FROM outfits"); + + return extractCount(rs); + } + + private static int countDeletedOutfitsExec() throws SQLException { + ResultSet rs = FSDB.get().select("SELECT COUNT(*) AS count FROM outfits WHERE deleted = 1"); + + return extractCount(rs); + } + + private static int countActiveOutfitsExec() throws SQLException { + ResultSet rs = FSDB.get().select("SELECT COUNT(*) AS count FROM outfits WHERE deleted = 0"); + + return extractCount(rs); + } + + private static int countFeaturedOutfitsExec() throws SQLException { + ResultSet rs = FSDB.get().select("SELECT COUNT(*) AS count FROM outfits WHERE featured = 1"); + + return extractCount(rs); + } + + private static int countOutfitsExec(boolean deleted, boolean featured) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT COUNT(*) AS count FROM outfits WHERE deleted = ? AND featured = ?", deleted, featured); + + return extractCount(rs); + } + + private static int countOutfitsBySubmitterExec(String submitterId) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT COUNT(*) AS count FROM outfits WHERE submitter = ? AND deleted = 0", submitterId); + + return extractCount(rs); + } + + private static Collection getDistinctTagsExec() throws SQLException { + ResultSet rs = FSDB.get().select("SELECT DISTINCT tag FROM outfits"); + + Collection tags = new ArrayList<>(); + while (rs.next()) { + tags.add(rs.getString("tag")); + } + + FSDB.get().close(rs); + return tags; + } + + private static void updateExec(Outfit outfit) throws SQLException { + FSDB.get().query("UPDATE outfits SET " + + "link = ?," + + "submitter = ?," + + "tag = ?," + + "meta = ?," + + "updated = ?," + + "featured = ?," + + "display_count = ?" + + "WHERE id = ?", + outfit.getLink(), + outfit.getSubmitter(), + outfit.getTag(), + outfit.getMeta(), + outfit.getUpdated(), + outfit.isFeatured(), + outfit.getDisplayCount(), + outfit.getId()); + } + + private static void deleteExec(String id) throws SQLException { + FSDB.get().query("UPDATE outfits SET deleted = true WHERE id = ?", id); + } + + private static Optional> extractMultiple(ResultSet rs) throws SQLException { + Collection outfits = new ArrayList<>(); + + while (rs.next()) { + outfits.add(mapObject(rs)); + } + + FSDB.get().close(rs); + + if (outfits.size() == 0) { + return Optional.empty(); + } + + return Optional.of(outfits); + } + + private static int extractCount(ResultSet rs) throws SQLException { + int count = 0; + if (rs.next()) { + count = rs.getInt("count"); + } + + FSDB.get().close(rs); + return count; + } + + private static Outfit mapObject(ResultSet rs) throws SQLException { + return new Outfit.OutfitBuilder() + .setId(rs.getString("id")) + .setLink(rs.getString("link")) + .setSubmitter(rs.getString("submitter")) + .setTag(rs.getString("tag")) + .setMeta(rs.getString("meta")) + .setCreated(new Timestamp(rs.getLong("created"))) + .setUpdated(new Timestamp((rs.getLong("updated")))) + .setDeleted(rs.getBoolean("deleted")) + .setFeatured(rs.getBoolean("featured")) + .setDisplayCount(rs.getInt("display_count")) + .setDeleteHash(rs.getString("delete_hash")) + .build(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerBlacklistController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerBlacklistController.java new file mode 100644 index 0000000..c32a839 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerBlacklistController.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.controllers; + +import dev.salmonllama.fsbot.database.FSDB; +import dev.salmonllama.fsbot.database.models.ServerBlacklist; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +public class ServerBlacklistController { + // Need to create, read, and delete. No need for update? + public static CompletableFuture insert(ServerBlacklist bl) { + return CompletableFuture.runAsync(() -> { + try { + insertExec(bl); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture exists(String id) { + return CompletableFuture.supplyAsync(() -> { + try { + return existsExec(id); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture exists(ServerBlacklist bl) { + return CompletableFuture.supplyAsync(() -> { + try { + return existsExec(bl.getId()); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> get(String id) { + return CompletableFuture.supplyAsync(() -> { + try { + return getExec(id); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture delete(String id) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(id); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture delete(ServerBlacklist bl) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(bl.getId()); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + private static void insertExec(ServerBlacklist bl) throws SQLException { + // TODO: Check for null added timestamp and init + FSDB.get().insert("INSERT INTO blacklist_servers ('id', 'name', 'owner_id', 'added') VALUES (?, ?, ?, ?)", + bl.getId(), + bl.getName(), + bl.getOwnerId(), + bl.getAdded() + ); + } + + private static boolean existsExec(String id) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT EXISTS(SELECT 1 FROM blacklist_servers WHERE id = ?) AS hmm", id); + boolean exists = rs.getBoolean("hmm"); + + FSDB.get().close(rs); + return exists; + } + + private static Optional getExec(String id) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM blacklist_servers WHERE id = ?", id); + + if (rs.next()) { + ServerBlacklist bl = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(bl); + } + + FSDB.get().close(rs); + return Optional.empty(); + } + + private static void deleteExec(String id) throws SQLException { + FSDB.get().query("DELETE FROM blacklist_servers WHERE id = ?", id); + } + + private static ServerBlacklist mapObject(ResultSet rs) throws SQLException { + return new ServerBlacklist.ServerBlacklistBuilder(rs.getString("id")) + .setName(rs.getString("name")) + .setOwnerId(rs.getString("owner_id")) + .setAdded(new Timestamp(rs.getLong("added"))) + .build(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerConfigController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerConfigController.java new file mode 100644 index 0000000..c88a155 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/ServerConfigController.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.controllers; + +import dev.salmonllama.fsbot.database.FSDB; +import dev.salmonllama.fsbot.database.models.ServerConfig; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +public class ServerConfigController { + // insert + // retrieve + // update + // No need for delete -> guilds should persist after leaving. + + public static CompletableFuture insert(ServerConfig config) { + return CompletableFuture.runAsync(() -> { + try { + insertExec(config); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> get(String serverId) { + return CompletableFuture.supplyAsync(() -> { + try { + return getExec(serverId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture update(ServerConfig config) { + return CompletableFuture.runAsync(() -> { + try { + updateExec(config); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + private static void insertExec(ServerConfig config) throws SQLException { + FSDB.get().insert("INSERT INTO server_config(id, prefix, welcome_message) VALUES (?, ?, ?)", + config.getId(), + config.getPrefix(), + config.getWelcomeMessage() + ); + } + + private static Optional getExec(String serverId) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM server_config WHERE id = ?", serverId); + + if (rs.next()) { + ServerConfig config = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(config); + } + + FSDB.get().close(rs); + return Optional.empty(); + } + + private static void updateExec(ServerConfig config) throws SQLException { + FSDB.get().query("UPDATE server_config SET prefix = ?, welcome_message = ?, welcome_channel = ?, WHERE id = ?", + config.getPrefix(), + config.getWelcomeMessage(), + config.getWelcomeChannel(), + config.getId() + ); + } + + private static ServerConfig mapObject(ResultSet rs) throws SQLException { + return new ServerConfig.ServerConfigBuilder() + .setId(rs.getString("id")) + .setPrefix(rs.getString("prefix")) + .setWelcomeMessage(rs.getString("welcome_message")) + .setWelcomeChannel(rs.getString("welcome_channel")) + .build(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/StaticPermissionController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/StaticPermissionController.java new file mode 100644 index 0000000..027337a --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/StaticPermissionController.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.controllers; + +import dev.salmonllama.fsbot.database.FSDB; +import dev.salmonllama.fsbot.database.models.StaticPermission; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +public class StaticPermissionController { + // Need to insert, get all per user, get per keyword, and delete + public static CompletableFuture insert(StaticPermission perm) { + return CompletableFuture.runAsync(() -> { + try { + insertExec(perm); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture>> getByUser(String userId) { + return CompletableFuture.supplyAsync(() -> { + try { + return getByUserExec(userId); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture>> getByPermission(String perm) { + return CompletableFuture.supplyAsync(() -> { + try { + return getByPermissionExec(perm); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture>> getAll() { + return CompletableFuture.supplyAsync(() -> { + try { + return getAllExec(); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture delete(StaticPermission perm) { + return delete(perm.getUserId(), perm.getPermission()); + } + + public static CompletableFuture delete(String userId, String perm) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(userId, perm); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + private static void insertExec(StaticPermission perm) throws SQLException { + if (perm.getAdded() == null) { + perm.setAdded(new Timestamp(System.currentTimeMillis())); + } + + FSDB.get().insert("INSERT INTO static_permissions (user_id, permission, date_added) VALUES (?, ?, ?)", + perm.getUserId(), + perm.getPermission(), + perm.getAdded() + ); + } + + private static Optional> getByUserExec(String userId) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM static_permissions WHERE user_id = ?", userId); + + Collection permissions = new ArrayList<>(); + while (rs.next()) { + permissions.add(mapObject(rs)); + } + + FSDB.get().close(rs); + + if (permissions.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(permissions); + } + + private static Optional> getByPermissionExec(String perm) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM static_permissions WHERE permission = ?", perm); + + Collection users = new ArrayList<>(); + while (rs.next()) { + users.add(mapObject(rs)); + } + + FSDB.get().close(rs); + + if (users.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(users); + } + + private static Optional> getAllExec() throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM static_permissions"); + + Collection permissions = new ArrayList<>(); + while (rs.next()) { + permissions.add(mapObject(rs)); + } + + FSDB.get().close(rs); + + if (permissions.isEmpty()) { + return Optional.empty(); + } + + return Optional.of(permissions); + } + + private static void deleteExec(String userId, String perm) throws SQLException { + FSDB.get().query("DELETE FROM static_permissions WHERE user_id = ? AND permission = ?", userId, perm); + } + + private static StaticPermission mapObject(ResultSet rs) throws SQLException { + return new StaticPermission.StaticPermissionBuilder(rs.getString("user_id")) + .setPermission(rs.getString("permission")) + .setAdded(new Timestamp(rs.getLong("date_added"))) + .build(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/controllers/UserBlacklistController.java b/src/main/java/dev/salmonllama/fsbot/database/controllers/UserBlacklistController.java new file mode 100644 index 0000000..fbbb0e2 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/controllers/UserBlacklistController.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.controllers; + +import dev.salmonllama.fsbot.database.FSDB; +import dev.salmonllama.fsbot.database.models.ServerBlacklist; +import dev.salmonllama.fsbot.database.models.UserBlacklist; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; + +public class UserBlacklistController { + // Need to create, read, and delete. No need for update? + // Exists, insert, get, delete + public static CompletableFuture insert(UserBlacklist bl) { + return CompletableFuture.runAsync(() -> { + try { + insertExec(bl); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture exists(String id) { + return CompletableFuture.supplyAsync(() -> { + try { + return existsExec(id); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture exists(UserBlacklist bl) { + return CompletableFuture.supplyAsync(() -> { + try { + return existsExec(bl.getId()); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture> get(String id) { + return CompletableFuture.supplyAsync(() -> { + try { + return getExec(id); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + + public static CompletableFuture delete(String id) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(id); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + public static CompletableFuture delete(UserBlacklist bl) { + return CompletableFuture.runAsync(() -> { + try { + deleteExec(bl.getId()); + } catch (SQLException e) { + throw new CompletionException(e); + } + }); + } + + private static void insertExec(UserBlacklist bl) throws SQLException { + if (bl.getAdded() == null) { + bl.setAdded(new Timestamp(System.currentTimeMillis())); + } + + FSDB.get().insert("INSERT INTO blacklist_users ('id', 'reason', 'added') VALUES (?, ?, ?)", + bl.getId(), + bl.getReason(), + bl.getAdded() + ); + } + + private static boolean existsExec(String id) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT EXISTS(SELECT 1 FROM blacklist_users WHERE id = ?) AS hmm", id); + boolean exists = rs.getBoolean("hmm"); + + FSDB.get().close(rs); + return exists; + } + + private static Optional getExec(String id) throws SQLException { + ResultSet rs = FSDB.get().select("SELECT * FROM blacklist_users WHERE id = ?", id); + + if (rs.next()) { + UserBlacklist bl = mapObject(rs); + FSDB.get().close(rs); + return Optional.of(bl); + } + + FSDB.get().close(rs); + return Optional.empty(); + } + + private static void deleteExec(String id) throws SQLException { + FSDB.get().query("DELETE FROM blacklist_users WHERE id = ?", id); + } + + private static UserBlacklist mapObject(ResultSet rs) throws SQLException { + return new UserBlacklist.UserBlacklistBuilder(rs.getString("id")) + .setReason(rs.getString("reason")) + .setAdded(new Timestamp(rs.getLong("added"))) + .build(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/models/ColorRole.java b/src/main/java/dev/salmonllama/fsbot/database/models/ColorRole.java new file mode 100644 index 0000000..39ff347 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/models/ColorRole.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +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; + + public ColorRole(ColorRoleBuilder builder) { + roleId = builder.roleId; + serverId = builder.serverId; + color = builder.color; + } + + public long getRoleId() { + return roleId; + } + + public long getServerId() { + return serverId; + } + + public String getColor() { + return color; + } + + public static String schema() { + return "CREATE TABLE IF NOT EXISTS color_roles (role_id INTEGER, server_id INTEGER, color TEXT)"; + } + + public static class ColorRoleBuilder { + private long roleId; + private long serverId; + private String color; + + public ColorRoleBuilder(long roleId) { + this.roleId = roleId; + } + + public ColorRoleBuilder setServerId(long serverId) { + this.serverId = serverId; + return this; + } + + public ColorRoleBuilder setColor(String color) { + this.color = color; + return this; + } + + public ColorRole build() { + return new ColorRole(this); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/models/GalleryChannel.java b/src/main/java/dev/salmonllama/fsbot/database/models/GalleryChannel.java new file mode 100644 index 0000000..5ae2d2d --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/models/GalleryChannel.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.models; + +import dev.salmonllama.fsbot.database.DatabaseModel; + +public class GalleryChannel extends DatabaseModel { + private final String serverId; + private final String channelId; + private final String tag; + // Normal emojis will be stored in plain text as :emoji: + // Server emojis will be stored in plain text as <:emoji:emoji-id> + // This can be acquired through CustomEmoji#getMentionTag() + private final String emoji; + + public GalleryChannel(GalleryBuilder builder) { + serverId = builder.serverId; + channelId = builder.channelId; + tag = builder.tag; + emoji = builder.emoji; + } + + public String getServerId() { + return serverId; + } + + public String getChannelId() { + return channelId; + } + + + public String getTag() { + return tag; + } + + public String getEmoji() { + return emoji; + } + + public static String schema() { + return "CREATE TABLE IF NOT EXISTS galleries (" + + "server_id TEXT," + + "channel_id TEXT," + + "emoji TEXT," + + "tag TEXT)"; + } + + @Override + public String toString() { + return String.format("Gallery: [server id: %s, channel id: %s, tag: %s, emoji: %s]", + serverId, channelId, tag, emoji); + } + + public static class GalleryBuilder { + private String serverId; + private String channelId; + private String tag; + private String emoji; + + public GalleryBuilder() { + + } + public GalleryBuilder setServerId(String serverId) { + this.serverId = serverId; + return this; + } + + public GalleryBuilder setChannelId(String channelId) { + this.channelId = channelId; + return this; + } + + public GalleryBuilder setTag(String tag) { + this.tag = tag; + return this; + } + + public GalleryBuilder setEmoji(String emoji) { + this.emoji = emoji; + return this; + } + + public GalleryChannel build() { + return new GalleryChannel(this); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/models/Outfit.java b/src/main/java/dev/salmonllama/fsbot/database/models/Outfit.java new file mode 100644 index 0000000..6791f5d --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/models/Outfit.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.models; + +import dev.salmonllama.fsbot.database.DatabaseModel; + +import java.sql.Timestamp; + +public class Outfit extends DatabaseModel { + private String id; + private String link; + private String submitter; + private String tag; + private String meta; + private Timestamp created; + private Timestamp updated; + private boolean deleted; + private boolean featured; + private int displayCount; + private String deleteHash; + + public Outfit(OutfitBuilder builder) { + id = builder.id; + link = builder.link; + submitter = builder.submitter; + tag = builder.tag; + meta = builder.meta; + created = builder.created; + updated = builder.updated; + deleted = builder.deleted; + featured = builder.featured; + displayCount = builder.displayCount; + deleteHash = builder.deleteHash; + } + + public String getId() { + return id; + } + + public String getLink() { + return link; + } + + public String getSubmitter() { + return submitter; + } + + public String getTag() { + return tag; + } + + public String getMeta() { + return meta; + } + + public Timestamp getCreated() { + return created; + } + + public void setCreated(Timestamp c) { + this.created = c; + } + + public Timestamp getUpdated() { + return updated; + } + + public void setUpdated(Timestamp u) { + this.updated = u; + } + + public boolean isDeleted() { + return deleted; + } + + public boolean isFeatured() { + return featured; + } + + public int getDisplayCount() { + return displayCount; + } + + public String getDeleteHash() { + return deleteHash; + } + + public static String schema() { + return "CREATE TABLE IF NOT EXISTS outfits (" + + "id TEXT, " + + "link TEXT," + + "submitter TEXT," + + "tag TEXT," + + "meta TEXT," + + "created TEXT," + + "updated TEXT," + + "deleted TEXT," + + "featured TEXT," + + "display_count INT," + + "delete_hash TEXT)"; + } + + @Override + public String toString() { + return String.format("Outfit: [id: %s, link: %s, submitter: %s, tag: %s, created: %s, updated: %s, deleted: %s, featured: %s, display count: %s, deletion hash: %s, meta: %s]", + id, link, submitter, tag, created, updated, deleted, featured, displayCount, deleteHash, meta + ); + } + + public static class OutfitBuilder { + private String id; + private String link; + private String submitter; + private String tag; + private String meta; + private Timestamp created = null; + private Timestamp updated = null; + private boolean deleted = false; + private boolean featured = false; + private int displayCount = 0; + private String deleteHash = ""; + + public OutfitBuilder() { + } + + public OutfitBuilder(Outfit outfit) { + this.id = outfit.getId(); + this.link = outfit.getLink(); + this.submitter = outfit.getSubmitter(); + this.tag = outfit.getTag(); + this.meta = outfit.getMeta(); + this.created = outfit.getCreated(); + this.updated = outfit.getUpdated(); + this.deleted = outfit.isDeleted(); + this.featured = outfit.isFeatured(); + this.displayCount = outfit.getDisplayCount(); + this.deleteHash = outfit.getDeleteHash(); + } + + public OutfitBuilder setId(String id) { + this.id = id; + return this; + } + + public OutfitBuilder setLink(String link) { + this.link = link; + return this; + } + + public OutfitBuilder setSubmitter(String submitter) { + this.submitter = submitter; + return this; + } + + public OutfitBuilder setTag(String tag) { + this.tag = tag; + return this; + } + + public OutfitBuilder setMeta(String meta) { + this.meta = meta; + return this; + } + + public OutfitBuilder setCreated(Timestamp created) { + this.created = created; + return this; + } + + public OutfitBuilder setUpdated(Timestamp updated) { + this.updated = updated; + return this; + } + + public OutfitBuilder setDeleted(boolean deleted) { + this.deleted = deleted; + return this; + } + + public OutfitBuilder setFeatured(boolean featured) { + this.featured = featured; + return this; + } + + public OutfitBuilder setDisplayCount(int displayCount) { + this.displayCount = displayCount; + return this; + } + + public OutfitBuilder setDeleteHash(String deletionHash) { + this.deleteHash = deletionHash; + return this; + } + + public Outfit build() { + return new Outfit(this); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/models/ServerBlacklist.java b/src/main/java/dev/salmonllama/fsbot/database/models/ServerBlacklist.java new file mode 100644 index 0000000..4aaeb92 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/models/ServerBlacklist.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.models; + +import dev.salmonllama.fsbot.database.DatabaseModel; + +import java.sql.Timestamp; + +public class ServerBlacklist extends DatabaseModel { // TODO: Add a reason? + private String id; + private String name; + private String ownerId; + private Timestamp added; + + private ServerBlacklist(ServerBlacklistBuilder builder) { + this.id = builder.id; + this.name = builder.name; + this.ownerId = builder.ownerId; + this.added = builder.added; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getOwnerId() { + return ownerId; + } + + public Timestamp getAdded() { + return added; + } + + public static String schema() { + return "CREATE TABLE IF NOT EXISTS blacklist_servers (" + + "id TEXT PRIMARY KEY," + + "name TEXT," + + "owner_id TEXT," + + "added TEXT)"; + } + + @Override + public String toString() { + return String.format("Server Blacklist: [id: %s, name: %s, owner_id: %s, added %s]", + this.getId(), + this.getName(), + this.getOwnerId(), + this.getAdded() + ); + } + + public static class ServerBlacklistBuilder { + private String id; + private String name; + private String ownerId; + private Timestamp added; + + public ServerBlacklistBuilder(String id) { + this.id = id; + } + + public ServerBlacklistBuilder setName(String name) { + this.name = name; + return this; + } + + public ServerBlacklistBuilder setOwnerId(String ownerId) { + this.ownerId = ownerId; + return this; + } + + public ServerBlacklistBuilder setAdded(Timestamp added) { + this.added = added; + return this; + } + + public ServerBlacklist build() { + return new ServerBlacklist(this); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/models/ServerConfig.java b/src/main/java/dev/salmonllama/fsbot/database/models/ServerConfig.java new file mode 100644 index 0000000..0230cd3 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/models/ServerConfig.java @@ -0,0 +1,91 @@ +package dev.salmonllama.fsbot.database.models; + +import dev.salmonllama.fsbot.database.DatabaseModel; + +public class ServerConfig extends DatabaseModel { + private final String id; + private final String prefix; + private final String welcomeMessage; + private final String welcomeChannel; + + public ServerConfig(ServerConfigBuilder builder) { + this.id = builder.id; + this.prefix = builder.prefix; + this.welcomeMessage = builder.welcomeMessage; + this.welcomeChannel = builder.welcomeChannel; + } + + public String getId() { + return id; + } + + public String getPrefix() { + return prefix; + } + + public String getWelcomeMessage() { + return welcomeMessage; + } + + public String getWelcomeChannel() { + return welcomeChannel; + } + + public static String schema() { + return "CREATE TABLE IF NOT EXISTS server_config (" + + "id TEXT," + + "prefix TEXT," + + "welcome_message TEXT," + + "welcome_channel TEXT)"; + } + + @Override + public String toString() { + return String.format("Server Config: [id: %s, prefix: %s, welcome_message: %s, welcome_channel: %s]", + id, prefix, welcomeMessage, welcomeChannel + ); + } + + public static class ServerConfigBuilder { + private String id; + private String prefix; + private String welcomeMessage; + private String welcomeChannel; + + public ServerConfigBuilder() { + + } + + public ServerConfigBuilder from(ServerConfig config) { + this.id = config.id; + this.prefix = config.prefix; + this.welcomeMessage = config.welcomeMessage; + this.welcomeChannel = config.welcomeChannel; + return this; + } + + public ServerConfigBuilder setId(String id) { + this.id = id; + return this; + } + + public ServerConfigBuilder setPrefix(String prefix) { + this.prefix = prefix; + return this; + } + + public ServerConfigBuilder setWelcomeMessage(String welcomeMessage) { + this.welcomeMessage = welcomeMessage; + return this; + } + + public ServerConfigBuilder setWelcomeChannel(String welcomeChannel) { + this.welcomeChannel = welcomeChannel; + return this; + } + + public ServerConfig build() { + return new ServerConfig(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/dev/salmonllama/fsbot/database/models/StaticPermission.java b/src/main/java/dev/salmonllama/fsbot/database/models/StaticPermission.java new file mode 100644 index 0000000..273f44a --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/models/StaticPermission.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.models; + +import dev.salmonllama.fsbot.database.DatabaseModel; + +import java.sql.Timestamp; +import java.time.Instant; + +public class StaticPermission extends DatabaseModel { + private String userId; + private String permission; + private Timestamp added; + + private StaticPermission(StaticPermissionBuilder builder) { + userId = builder.userId; + permission = builder.permission; + added = builder.added; + } + + public String getUserId() { + return userId; + } + + public String getPermission() { + return permission; + } + + public Timestamp getAdded() { + return added; + } + + public void setAdded(Timestamp added) { + this.added = added; + } + + public static String schema() { + return "CREATE TABLE IF NOT EXISTS static_permissions (user_id TEXT, permission TEXT, date_added TEXT)"; + } + + @Override + public String toString() { + return String.format("Static Permission [userId: %s, permission: %s, added: %s", userId, permission, added.toString()); + } + + public static class StaticPermissionBuilder { + private String userId; + private String permission = null; + private Timestamp added = null; + + public StaticPermissionBuilder(String userId) { + this.userId = userId; + } + + public StaticPermissionBuilder setPermission(String permission) { + this.permission = permission; + return this; + } + + public StaticPermissionBuilder setAdded(Timestamp added) { + this.added = added; + return this; + } + + public StaticPermission build() { + return new StaticPermission(this); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/database/models/UserBlacklist.java b/src/main/java/dev/salmonllama/fsbot/database/models/UserBlacklist.java new file mode 100644 index 0000000..1b138d9 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/database/models/UserBlacklist.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.database.models; + +import dev.salmonllama.fsbot.database.DatabaseModel; + +import java.sql.Timestamp; + +public class UserBlacklist extends DatabaseModel { + private String id; + private String reason; + private Timestamp added; + + private UserBlacklist(UserBlacklistBuilder builder) { + this.id = builder.id; + this.reason = builder.reason; + this.added = builder.added; + } + + public String getId() { + return id; + } + + public String getReason() { + return reason; + } + + public Timestamp getAdded() { + return added; + } + + public void setAdded(Timestamp added) { + this.added = added; + } + + public static String schema() { + return "CREATE TABLE IF NOT EXISTS blacklist_users (" + + "id TEXT PRIMARY KEY," + + "reason TEXT," + + "added TEXT)"; + } + + @Override + public String toString() { + return String.format("User Blacklist: [id: %s, reason: %s, added: %s]", + this.getId(), + this.getReason(), + this.getAdded() + ); + } + + public static class UserBlacklistBuilder { + private String id; + private String reason; + private Timestamp added; + + public UserBlacklistBuilder(String id) { + this.id = id; + } + + public UserBlacklistBuilder setId(String id) { + this.id = id; + return this; + } + + public UserBlacklistBuilder setReason(String reason) { + this.reason = reason; + return this; + } + + public UserBlacklistBuilder setAdded(Timestamp added) { + this.added = added; + return this; + } + + public UserBlacklist build() { + return new UserBlacklist(this); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/endpoints/imgur/ImgurAPIConnection.java b/src/main/java/dev/salmonllama/fsbot/endpoints/imgur/ImgurAPIConnection.java new file mode 100644 index 0000000..ff7417b --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/endpoints/imgur/ImgurAPIConnection.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.endpoints.imgur; + +import dev.salmonllama.fsbot.config.BotConfig; +import okhttp3.*; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +public class ImgurAPIConnection { + private final String REQUEST_URL = "https://api.imgur.com/3/image/"; + + private final String CLIENT_ID; // Required for uploading + private final String BEARER_TOKEN; // Required for deleting + + // Create the okhttp objects. Use methods to complete requests. + private final OkHttpClient client; + private final Request.Builder requestBuilder; + + public ImgurAPIConnection() { + CLIENT_ID = BotConfig.IMGUR_ID; + BEARER_TOKEN = BotConfig.IMGUR_BEARER; + + client = new OkHttpClient().newBuilder().build(); + requestBuilder = new Request.Builder(); + } + + public CompletableFuture uploadImage(String link) { + return CompletableFuture.supplyAsync(() -> uploadImageExec(link)); + } + + public CompletableFuture deleteImage(String deleteHash) { + return CompletableFuture.supplyAsync(() -> deleteImageExec(deleteHash)); + } + + private ImgurUpload uploadImageExec(String discordLink) { + RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("image", discordLink).build(); + + Request request = requestBuilder + .url(REQUEST_URL) + .method("POST", body) + .addHeader("Authorization", CLIENT_ID) + .build(); + + JSONObject json; + try (Response response = client.newCall(request).execute()) { + json = new JSONObject(response.body().string()).getJSONObject("data"); + } catch (IOException e) { + e.printStackTrace(); // TODO: Do tha logging thang. + return null; + } + + return new ImgurUpload.ImgurUploadBuilder() + .setId(json.getString("id")) + .setDateTime(json.getLong("datetime")) + .setDeleteHash(json.getString("deletehash")) + .setLink(json.getString("link")) + .build(); + } + + private boolean deleteImageExec(String deleteHash) { + RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM).build(); + + Request request = requestBuilder + .url(REQUEST_URL.concat(deleteHash)) + .method("DELETE", body) + .addHeader("Authorization", BEARER_TOKEN) + .build(); + + boolean success; + try (Response response = client.newCall(request).execute()) { + success = new JSONObject(response.body().string()).getBoolean("success"); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + return success; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/endpoints/imgur/ImgurUpload.java b/src/main/java/dev/salmonllama/fsbot/endpoints/imgur/ImgurUpload.java new file mode 100644 index 0000000..59252d3 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/endpoints/imgur/ImgurUpload.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.endpoints.imgur; + +public class ImgurUpload { + private final String id; + private final long dateTime; + private final String deleteHash; + private final String link; + + public ImgurUpload(ImgurUploadBuilder builder) { + id = builder.id; + dateTime = builder.dateTime; + deleteHash = builder.deleteHash; + link = builder.link; + } + + public String getId() { + return id; + } + + public long getDateTime() { + return dateTime; + } + + public String getDeleteHash() { + return deleteHash; + } + + public String getLink() { + return link; + } + + public static class ImgurUploadBuilder { + private String id; + private long dateTime; + private String deleteHash; + private String link; + + public ImgurUploadBuilder() { + + } + + public ImgurUploadBuilder setId(String id) { + this.id = id; + return this; + } + + public ImgurUploadBuilder setDateTime(long dateTime) { + this.dateTime = dateTime; + return this; + } + + public ImgurUploadBuilder setDeleteHash(String deleteHash) { + this.deleteHash = deleteHash; + return this; + } + + public ImgurUploadBuilder setLink(String link) { + this.link = link; + return this; + } + + public ImgurUpload build() { + return new ImgurUpload(this); + } + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/exceptions/FailedUploadException.java b/src/main/java/dev/salmonllama/fsbot/exceptions/FailedUploadException.java new file mode 100644 index 0000000..b496191 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/exceptions/FailedUploadException.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.exceptions; + +public class FailedUploadException extends Exception { + private String message; + + public FailedUploadException(String imageLink) { + message = "Failed to upload: ".concat(imageLink); + } + + @Override + public String toString() { + return message; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/exceptions/UnknownParameterException.java b/src/main/java/dev/salmonllama/fsbot/exceptions/UnknownParameterException.java new file mode 100644 index 0000000..9972698 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/exceptions/UnknownParameterException.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.exceptions; + +import java.sql.SQLException; + +public class UnknownParameterException extends SQLException { + private String message; + + public UnknownParameterException(Object param) { + message = "Unknown parameter type: " + param; + } + + public UnknownParameterException(Object param, int index) { + message = String.format("Unknown parameter type %s at %d", param, index); + } + + @Override + public String toString() { + return message; + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/Command.java b/src/main/java/dev/salmonllama/fsbot/guthix/Command.java index 2479c8a..92c8df8 100644 --- a/src/main/java/dev/salmonllama/fsbot/guthix/Command.java +++ b/src/main/java/dev/salmonllama/fsbot/guthix/Command.java @@ -6,6 +6,7 @@ package dev.salmonllama.fsbot.guthix; import java.util.Collection; +import java.util.concurrent.CompletableFuture; public abstract class Command { public abstract String name(); @@ -18,7 +19,6 @@ public abstract class Command { public abstract void onCommand(CommandContext ctx); public void invoke(final CommandContext ctx) { - Thread thread = new Thread(() -> onCommand(ctx)); - thread.start(); + CompletableFuture.runAsync(() -> onCommand(ctx)); } } diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/CommandContext.java b/src/main/java/dev/salmonllama/fsbot/guthix/CommandContext.java index a59b78d..f997a1c 100644 --- a/src/main/java/dev/salmonllama/fsbot/guthix/CommandContext.java +++ b/src/main/java/dev/salmonllama/fsbot/guthix/CommandContext.java @@ -125,6 +125,7 @@ public class CommandContext { String usedAlias, String[] args ) { + this.event = event; this.api = event.getApi(); this.message = event.getMessage(); this.author = event.getMessageAuthor(); diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/Guthix.java b/src/main/java/dev/salmonllama/fsbot/guthix/Guthix.java index fff490c..e65f7ae 100644 --- a/src/main/java/dev/salmonllama/fsbot/guthix/Guthix.java +++ b/src/main/java/dev/salmonllama/fsbot/guthix/Guthix.java @@ -5,47 +5,33 @@ package dev.salmonllama.fsbot.guthix; -import dev.salmonllama.fsbot.commands.general.HelpCommand; -import dev.salmonllama.fsbot.commands.general.SpecificOutfitCommand; +import dev.salmonllama.fsbot.commands.developer.*; +import dev.salmonllama.fsbot.commands.general.*; 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 + * Guthix is Fashionscape Bot's command repository and dispatcher */ public class Guthix implements MessageCreateListener { + @SuppressWarnings("unused") private DiscordApi api; - private DatabaseUtilities db; private Registry registry; private PermissionManager manager; - public Guthix(DiscordApi api, DatabaseUtilities db) { + public Guthix(DiscordApi api) { this.api = api; api.addMessageCreateListener(this); - this.db = db; - - manager = new PermissionManager(api); + manager = new PermissionManager(); registry = new Registry(); initCommands(); @@ -54,28 +40,30 @@ public class Guthix implements MessageCreateListener { public void initCommands() { // Developer Commands addCommand(new TestCommand()); - addCommand(new EvalCommand(db)); addCommand(new CreateGalleryCommand()); addCommand(new InviteCommand()); + addCommand(new PermissionCommand()); // 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 RetagCommand()); + addCommand(new RemoveOutfitCommand()); + addCommand(new OutfitInfoCommand()); addCommand(new SetStatusCommand()); addCommand(new WelcomeMessageCommand()); + addCommand(new ShowGalleriesCommand()); // General Commands addCommand(new PingCommand()); addCommand(new ColorCommand()); addCommand(new ColorsCommand()); - addCommand(new OutfitCommand(db)); - addCommand(new SpecificOutfitCommand(db)); + addCommand(new OutfitCommand()); addCommand(new HelpCommand(this)); + addCommand(new StatsCommand()); + addCommand(new PrivacyCommand()); } public void addCommand(Command cmd) { @@ -101,29 +89,27 @@ public class Guthix implements MessageCreateListener { return; } - String content = event.getMessageContent().toLowerCase(); + String content = event.getMessageContent(); + String contentLower = content.toLowerCase(); - if (registry.startsWithPrefix(content)) { + if (registry.startsWithPrefix(contentLower)) { } else { return; } RegistryCommand rComm = registry.getCommandInfo(content); - String cmdString = rComm.getCommand(); + String cmdString = rComm.getCommand().toLowerCase(); - if (registry.isCommandAlias(cmdString)) { +// if (registry.isCommandAlias(cmdString)) { +// +// } else { +// return; +// } - } else { - return; - } - - Message msg = event.getMessage(); - TextChannel channel = event.getChannel(); - Server server = event.getServer().orElse(null); String[] cmdArgs = rComm.getArgs(); - Command cmd = registry.findCommand(cmdString).orElse(null); // TODO: default command here + Command cmd = registry.findCommand(cmdString).orElse(new DefaultCommand()); // TODO: default command here CommandContext ctx = new CommandContext.CommandContextBuilder( event, diff --git a/src/main/java/dev/salmonllama/fsbot/guthix/PermissionManager.java b/src/main/java/dev/salmonllama/fsbot/guthix/PermissionManager.java index 5ea944b..fb2bc9e 100644 --- a/src/main/java/dev/salmonllama/fsbot/guthix/PermissionManager.java +++ b/src/main/java/dev/salmonllama/fsbot/guthix/PermissionManager.java @@ -5,35 +5,42 @@ package dev.salmonllama.fsbot.guthix; -import org.javacord.api.DiscordApi; +import java.util.concurrent.atomic.AtomicBoolean; + import org.javacord.api.entity.message.MessageAuthor; -public class PermissionManager { - private DiscordApi api; +import dev.salmonllama.fsbot.database.controllers.StaticPermissionController; +import dev.salmonllama.fsbot.database.models.StaticPermission; - public PermissionManager(DiscordApi api) { - this.api = api; +public class PermissionManager { + + public PermissionManager() { } public boolean hasPermission(CommandPermission reqPerm, CommandContext ctx) { - PermissionType permtype = reqPerm.getType(); + PermissionType permType = reqPerm.getType(); + String permValue = reqPerm.getValue(); - switch (permtype) { + 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); + return roleHandler(permValue, ctx); + case STATIC: + return staticHandler(permValue, ctx); + case PERMISSION: + return permissionHandler(ctx); case OWNER: // If the author is the owner, yes. return ownerHandler(ctx); + default: + return false; } - - return false; } private boolean roleHandler(String roleId, CommandContext ctx) { - if (!ctx.getUserRoles().isPresent()) { + if (ctx.getUserRoles().isEmpty()) { ctx.reply("This command can only be used in a server"); return false; } @@ -44,6 +51,27 @@ public class PermissionManager { return ctx.isUserOwner(); } + private boolean permissionHandler(CommandContext ctx) { + // Not implemented yet + return false; + } + + private boolean staticHandler(String staticPerm, CommandContext ctx) { + AtomicBoolean ret = new AtomicBoolean(false); + + StaticPermissionController.getByUser(ctx.getAuthor().getIdAsString()).thenAccept(possiblePerms -> { + possiblePerms.ifPresent(staticPermissions -> { + for (StaticPermission perm : staticPermissions) { + if (perm.getPermission().equals(staticPerm)) { + ret.set(true); + } + } + }); + }).join(); // TODO: Figure out a way to have this not join + + return ret.get(); + } + 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 index b20e97b..bafca5e 100644 --- a/src/main/java/dev/salmonllama/fsbot/guthix/PermissionType.java +++ b/src/main/java/dev/salmonllama/fsbot/guthix/PermissionType.java @@ -7,6 +7,8 @@ package dev.salmonllama.fsbot.guthix; public enum PermissionType { ROLE, // User has a specific role inside the server + PERMISSION, // User has a specific Discord permission bit + STATIC, // User has a pre-defined permission stored in the database 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 index 0496296..642790c 100644 --- a/src/main/java/dev/salmonllama/fsbot/guthix/Registry.java +++ b/src/main/java/dev/salmonllama/fsbot/guthix/Registry.java @@ -73,7 +73,6 @@ class Registry { if (input.contains(" ")) { input = removePrefix(input); String[] splits = input.split(" "); - System.out.println(Arrays.toString(splits)); return cleanSpaces(splits); } else { input = removePrefix(input); diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java index 0db9966..5a82e6c 100644 --- a/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ImageListener.java @@ -5,153 +5,99 @@ 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 dev.salmonllama.fsbot.config.BotConfig; +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.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 org.javacord.api.util.logging.ExceptionLogger; -import java.awt.*; -import java.util.List; +import java.sql.Timestamp; 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) { + public void onMessageCreate(MessageCreateEvent event) { // TODO: This needs immediate help + // 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) - event.getMessage().getUserAuthor().ifPresent(author -> { - if (author.isBot()) { - return; - } + if (!event.getMessageAuthor().isRegularUser()) { + // Ignore anything that is a webhook or a bot message + return; + } + + // Only works in Server Text Channels + event.getChannel().asServerTextChannel().ifPresent(channel -> { + // Only works in registered Gallery Channels + GalleryController.galleryExists(channel.getIdAsString()).thenAccept(exists -> { + 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 -> { + // 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()); + }); + } + } + }).exceptionally(ExceptionLogger.get()); }); - - 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(); - }); - }); - - if (dbTable.equals("disaster")) { - // Add custom panda emoji: <:PandaWut:433045737245376522> - message.addReaction("PandaWut:433045737245376522"); - } - - 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 index e7506a8..8ea2737 100644 --- a/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java +++ b/src/main/java/dev/salmonllama/fsbot/listeners/NewMemberListener.java @@ -5,33 +5,20 @@ package dev.salmonllama.fsbot.listeners; -import dev.salmonllama.fsbot.utilities.database.ServerConfUtility; -import org.javacord.api.DiscordApi; +import dev.salmonllama.fsbot.config.BotConfig; 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; + if (!event.getServer().getIdAsString().equals(BotConfig.HOME_SERVER)) { + return; + } - ServerConfUtility conf = new ServerConfUtility(event.getServer().getIdAsString()); - String welcomeMsg = conf.getWelcomeMsg(); - String welcomeChannel = conf.getWelcomeChannel(); +// String logMessage = String.format(welcomeMsg, event.getUser().getMentionTag()); - String logMessage = String.format(welcomeMsg, event.getUser().getMentionTag()); - - api.getChannelById(welcomeChannel).ifPresent(chnl -> { - chnl.asServerTextChannel().ifPresent(channel -> { - channel.sendMessage(logMessage); - }); - }); + event.getApi().getServerTextChannelById(BotConfig.WELCOME_CHANNEL).ifPresent(channel -> channel.sendMessage("Welcome!")); } } diff --git a/src/main/java/dev/salmonllama/fsbot/listeners/ReactionDeleteConfirmationListener.java b/src/main/java/dev/salmonllama/fsbot/listeners/ReactionDeleteConfirmationListener.java deleted file mode 100644 index a320213..0000000 --- a/src/main/java/dev/salmonllama/fsbot/listeners/ReactionDeleteConfirmationListener.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 deleted file mode 100644 index f1feeba..0000000 --- a/src/main/java/dev/salmonllama/fsbot/listeners/ReactionRetagConfirmationListener.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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/ServerJoined.java b/src/main/java/dev/salmonllama/fsbot/listeners/ServerJoined.java index 7ad7035..5f47903 100644 --- a/src/main/java/dev/salmonllama/fsbot/listeners/ServerJoined.java +++ b/src/main/java/dev/salmonllama/fsbot/listeners/ServerJoined.java @@ -5,31 +5,25 @@ 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) { + public ServerJoined(DiscordApi api) { this.api = api; - this.db = db; } - public void onServerJoin(ServerJoinEvent event) { - db.newServerProcess(event.getServer()); + public void onServerJoin(ServerJoinEvent event) { // TODO: This needs fixing yo + // 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()); + // 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/logging/Logger.java b/src/main/java/dev/salmonllama/fsbot/logging/Logger.java new file mode 100644 index 0000000..4d5c5ed --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/logging/Logger.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.logging; + +import dev.salmonllama.fsbot.config.BotConfig; +import org.javacord.api.DiscordApi; +import org.javacord.api.entity.message.embed.EmbedBuilder; + +import java.util.function.Function; + +public class Logger { + + private final DiscordApi api; + + 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 SALMONLLAMA = BotConfig.BOT_OWNER; + + private EmbedBuilder reportEmbed; + + private EmbedBuilder errorEmbed; + + public Logger(DiscordApi api) { + this.api = api; + } + + public void logOutfit() { + api.getServerTextChannelById(OUTFIT_LOG).ifPresentOrElse(channel -> { + // Log the thing + channel.sendMessage("outfit"); + }, () -> { + // DM me + api.getUserById(SALMONLLAMA).thenAcceptAsync(user -> { + user.sendMessage("Outfit log failed and was not found"); + }); + }); + } + + public void logReport() { + api.getServerTextChannelById(REPORT_LOG).ifPresentOrElse(channel -> { + // Log the thing + channel.sendMessage("report"); + }, () -> { + // DM me + api.getUserById(SALMONLLAMA).thenAcceptAsync(user -> { + user.sendMessage("Report log failed and was not found"); + }); + }); + } + + public void logError(String errorMsg) { + api.getServerTextChannelById(BOT_LOG).ifPresentOrElse(channel -> { + // Log the thing + channel.sendMessage("error"); + }, () -> { + // DM me + api.getUserById(SALMONLLAMA).thenAcceptAsync(user -> { + user.sendMessage("Error log failed and was not found"); + }); + }); + } + + public void logMovement() { + api.getServerTextChannelById(JOIN_LOG).ifPresentOrElse(channel -> { + // Log the thing + channel.sendMessage("User joined/Left"); + }, () -> { + // DM me + api.getUserById(SALMONLLAMA).thenAcceptAsync(user -> { + user.sendMessage("Movement log failed and was not found"); + }); + }); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/logging/ResponseType.java b/src/main/java/dev/salmonllama/fsbot/logging/ResponseType.java new file mode 100644 index 0000000..c5d381f --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/logging/ResponseType.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.logging; + +import java.awt.*; + +public enum ResponseType { + ERROR (Color.RED, "Error"), + WARN (Color.YELLOW, "Warning"), + INFO (Color.BLUE, "Info"), + LOG (Color.GRAY, "Log"); + + private Color color; + private String title; + ResponseType(Color color, String title) { + + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/logging/StandardEmbed.java b/src/main/java/dev/salmonllama/fsbot/logging/StandardEmbed.java new file mode 100644 index 0000000..f15c5a9 --- /dev/null +++ b/src/main/java/dev/salmonllama/fsbot/logging/StandardEmbed.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020. Aleksei Gryczewski + * All rights reserved. + */ + +package dev.salmonllama.fsbot.logging; + +import org.javacord.api.entity.message.embed.EmbedBuilder; + +public class StandardEmbed extends EmbedBuilder { + public StandardEmbed() { + super(); + } +} diff --git a/src/main/java/dev/salmonllama/fsbot/utilities/ColorRole.java b/src/main/java/dev/salmonllama/fsbot/utilities/ColorRole.java deleted file mode 100644 index 2a4bdf9..0000000 --- a/src/main/java/dev/salmonllama/fsbot/utilities/ColorRole.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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/Outfit.java b/src/main/java/dev/salmonllama/fsbot/utilities/Outfit.java deleted file mode 100644 index 7642bc1..0000000 --- a/src/main/java/dev/salmonllama/fsbot/utilities/Outfit.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 deleted file mode 100644 index 879eac2..0000000 --- a/src/main/java/dev/salmonllama/fsbot/utilities/database/DatabaseUtilities.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * 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 deleted file mode 100644 index be86216..0000000 --- a/src/main/java/dev/salmonllama/fsbot/utilities/database/RoleColourUtility.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 deleted file mode 100644 index 06c2cbf..0000000 --- a/src/main/java/dev/salmonllama/fsbot/utilities/database/ServerConfUtility.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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); - } -}