From cd3407e748773dbc2bc0f3953105d067c335cd50 Mon Sep 17 00:00:00 2001 From: Savvy Date: Sun, 19 Nov 2017 02:41:19 -0500 Subject: [PATCH] Fixed outstanding buds, added 3 additional commands, added ConversationModule and Discord Utils for Role / Member search --- pom.xml | 27 ++-- src/main/java/io/rixa/bot/Rixa.java | 69 ++++++--- .../java/io/rixa/bot/commands/Command.java | 3 +- .../rixa/bot/commands/cmds/HelpCommand.java | 33 +++- .../rixa/bot/commands/cmds/InfoCommand.java | 83 ++++++++++ .../rixa/bot/commands/cmds/PingCommand.java | 18 +++ .../bot/commands/cmds/ServerInfoCommand.java | 41 +++++ .../{ => handler}/CommandHandler.java | 10 +- .../commands/{ => perms}/RixaPermission.java | 15 +- .../bot/data/storage/DatabaseAdapter.java | 35 ++++- .../bot/data/storage/enums/Statements.java | 40 +++++ .../io/rixa/bot/events/BotJoinListener.java | 14 ++ .../io/rixa/bot/events/MessageListener.java | 48 ++++++ .../io/rixa/bot/events/ReadyListener.java | 6 +- .../java/io/rixa/bot/guild/RixaGuild.java | 10 +- .../rixa/bot/guild/manager/GuildManager.java | 28 +++- .../rixa/bot/guild/manager/GuildMapper.java | 15 +- .../io/rixa/bot/guild/manager/IGuild.java | 2 +- .../io/rixa/bot/guild/modules/RixaModule.java | 2 + .../modules/module/ConversationModule.java | 51 ++++++ .../guild/modules/module/LevelsModule.java | 12 +- .../java/io/rixa/bot/utils/DiscordUtils.java | 54 +++++++ .../io/rixa/bot/utils/MessageFactory.java | 146 ++++++++++++++++++ 23 files changed, 702 insertions(+), 60 deletions(-) create mode 100644 src/main/java/io/rixa/bot/commands/cmds/InfoCommand.java create mode 100644 src/main/java/io/rixa/bot/commands/cmds/PingCommand.java create mode 100644 src/main/java/io/rixa/bot/commands/cmds/ServerInfoCommand.java rename src/main/java/io/rixa/bot/commands/{ => handler}/CommandHandler.java (69%) rename src/main/java/io/rixa/bot/commands/{ => perms}/RixaPermission.java (56%) create mode 100644 src/main/java/io/rixa/bot/data/storage/enums/Statements.java create mode 100644 src/main/java/io/rixa/bot/events/BotJoinListener.java create mode 100644 src/main/java/io/rixa/bot/events/MessageListener.java create mode 100644 src/main/java/io/rixa/bot/guild/modules/module/ConversationModule.java create mode 100644 src/main/java/io/rixa/bot/utils/DiscordUtils.java create mode 100644 src/main/java/io/rixa/bot/utils/MessageFactory.java diff --git a/pom.xml b/pom.xml index f2a1dfd..28e7ebd 100644 --- a/pom.xml +++ b/pom.xml @@ -22,6 +22,12 @@ JDA LATEST + + mysql + mysql-connector-java + 5.1.38 + compile + com.fasterxml.jackson.dataformat jackson-dataformat-yaml @@ -48,6 +54,13 @@ 4.3.9.RELEASE compile + + + ca.pjer + chatter-bot-api + 1.4.7 + compile + @@ -72,24 +85,14 @@ org.apache.maven.plugins maven-shade-plugin - 2.4.3 + 3.0.0 package shade - - true - - - commons-logging:commons-logging - - ** - - - - + diff --git a/src/main/java/io/rixa/bot/Rixa.java b/src/main/java/io/rixa/bot/Rixa.java index bdb3c31..b86ddda 100644 --- a/src/main/java/io/rixa/bot/Rixa.java +++ b/src/main/java/io/rixa/bot/Rixa.java @@ -2,9 +2,17 @@ package io.rixa.bot; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import io.rixa.bot.commands.CommandHandler; +import io.rixa.bot.commands.cmds.InfoCommand; +import io.rixa.bot.commands.cmds.PingCommand; +import io.rixa.bot.commands.cmds.ServerInfoCommand; +import io.rixa.bot.commands.handler.CommandHandler; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.commands.cmds.HelpCommand; import io.rixa.bot.data.config.Configuration; import io.rixa.bot.data.storage.DatabaseAdapter; +import io.rixa.bot.events.BotJoinListener; +import io.rixa.bot.events.MessageListener; +import io.rixa.bot.events.ReadyListener; import io.rixa.bot.utils.FileUtils; import lombok.Getter; import net.dv8tion.jda.core.AccountType; @@ -12,6 +20,7 @@ import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDABuilder; import net.dv8tion.jda.core.OnlineStatus; import net.dv8tion.jda.core.entities.Game; +import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.exceptions.RateLimitedException; import net.dv8tion.jda.core.hooks.AnnotatedEventManager; @@ -31,7 +40,7 @@ public class Rixa { @Getter private List shardList; @Getter private File defaultPath; @Getter private Logger logger; - @Getter private JDA jda; + private static long timeUp; private Rixa() { instance = this; @@ -46,31 +55,42 @@ public class Rixa { loadJDA(); } + public static long getTimeUp() { + return timeUp; + } + private void loadJDA() { + JDABuilder jda = new JDABuilder(AccountType.BOT) + .setToken(configuration.getToken()) + .setGame(Game.of(configuration.getBotGame())) + .setEventManager(new AnnotatedEventManager()) + .addEventListener(new ReadyListener(), new BotJoinListener(), new MessageListener()) + .setAutoReconnect(true) + .setAudioEnabled(true) + .setEnableShutdownHook(false) + .setStatus(OnlineStatus.ONLINE); for (int i = 0; i < configuration.getShards(); i++) { - getLogger().info("Loading Shard #" + (i + 1) + "!"); try { - jda = new JDABuilder(AccountType.BOT) - .setToken(configuration.getToken()) - .setGame(Game.of(configuration.getBotGame())) - .setEventManager(new AnnotatedEventManager()) - .setAutoReconnect(true) - .setStatus(OnlineStatus.ONLINE) - .setAudioEnabled(true) - .setEnableShutdownHook(false) - .useSharding(i, configuration.getShards()) - .buildBlocking(); - getShardList().add(jda); - getLogger().info("Shard #" + (i + 1) + " has been loaded"); + getLogger().info("Loading Shard #" + (i + 1) + "!"); + getShardList().add(jda.useSharding(i, configuration.getShards()).buildBlocking()); + getLogger().info("Shard #" + (i + 1) + " has been loaded"); Thread.sleep(5000); - } catch (LoginException | RateLimitedException | InterruptedException e) { + } catch (InterruptedException | RateLimitedException | LoginException e) { e.printStackTrace(); } } Runtime.getRuntime().addShutdownHook(new Thread(() -> getShardList().forEach(JDA::shutdown))); + timeUp = System.currentTimeMillis(); } - private void registerCommands() {} + private void registerCommands() { + this.commandHandler.registerCommands( + new HelpCommand("help", RixaPermission.NONE, "Review commands and its usages!"), + new InfoCommand("info", RixaPermission.NONE, "Review information about a user or Rixa!"), + new ServerInfoCommand("serverinfo", RixaPermission.NONE, "Review information about the server!"), + new PingCommand("ping", RixaPermission.NONE, "Check Rixa's ping!") + ); + } private void loadConfiguration() { try { @@ -81,11 +101,24 @@ public class Rixa { File file = new File(defaultPath.getPath() + "/config.yml"); configuration = objectMapper.readValue(file, Configuration.class); logger.info("Configuration successfully loaded."); + DatabaseAdapter.getInstance().check(); } catch (IOException e) { logger.severe("Could not properly load configuration file!."); e.printStackTrace(); } - DatabaseAdapter.getInstance().check(); + } + + public Guild getGuildById(String id) { + Guild guild = null; + for (JDA jda : Rixa.getInstance().getShardList()) { + System.out.println(jda.getShardInfo().toString()); + System.out.println("JDA GUILDS:" + jda.getGuilds().size()); + if (jda == null || jda.getGuilds().size() == 0 || jda.getGuildById(id) == null) continue; + guild = jda.getGuildById(id); + break; + } + if (guild != null) return guild; + throw new NullPointerException("Guild not found."); } public static Rixa getInstance() { diff --git a/src/main/java/io/rixa/bot/commands/Command.java b/src/main/java/io/rixa/bot/commands/Command.java index 5417a35..3077b70 100644 --- a/src/main/java/io/rixa/bot/commands/Command.java +++ b/src/main/java/io/rixa/bot/commands/Command.java @@ -1,5 +1,6 @@ package io.rixa.bot.commands; +import io.rixa.bot.commands.perms.RixaPermission; import lombok.Getter; import lombok.Setter; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; @@ -31,5 +32,5 @@ public abstract class Command { setAliases(aliases); } - public abstract boolean execute(GuildMessageReceivedEvent event); + public abstract void execute(GuildMessageReceivedEvent event); } diff --git a/src/main/java/io/rixa/bot/commands/cmds/HelpCommand.java b/src/main/java/io/rixa/bot/commands/cmds/HelpCommand.java index 941a9f0..82b5a4c 100644 --- a/src/main/java/io/rixa/bot/commands/cmds/HelpCommand.java +++ b/src/main/java/io/rixa/bot/commands/cmds/HelpCommand.java @@ -1,8 +1,13 @@ package io.rixa.bot.commands.cmds; import io.rixa.bot.commands.Command; -import io.rixa.bot.commands.RixaPermission; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.entities.Message; import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.core.exceptions.ErrorResponseException; +import net.dv8tion.jda.core.exceptions.PermissionException; public class HelpCommand extends Command { @@ -11,7 +16,29 @@ public class HelpCommand extends Command { } @Override - public boolean execute(GuildMessageReceivedEvent event) { - return false; + public void execute(GuildMessageReceivedEvent event) { + try { + event.getMessage().delete().complete(); + } catch (PermissionException ignored) {} + EmbedBuilder embedBuilder = new EmbedBuilder(); + String stringBuilder = "\u2753" + + " **Help**" + + "\n" + + "Click the corresponding number for more information about the command menu."; + embedBuilder.setTitle(String.format("Help: %s", event.getGuild().getId())) + .setDescription(stringBuilder) + .addField("1 - General Commands", "Reveals usable commands intended for `everyone`", false) + .addField("2 - Staff Commands", "Reveals usable commands intended for `staff` use only", false) + .addField("3 - Music Commands", "Reveals usable commands to configure Rixa for your discord!", false) + .setColor(event.getMember().getColor()); + Message message = event.getAuthor().openPrivateChannel().complete().sendMessage(embedBuilder.build()).complete(); + MessageFactory.create(event.getMember().getAsMention() + + ", the help menu has been private messaged to you!").setColor(event.getMember().getColor()).queue(event.getChannel()); + try { + message.addReaction("\u0031\u20E3").queue(); + message.addReaction("\u0032\u20E3").queue(); + message.addReaction("\u0033\u20E3").queue(); + message.addReaction("\uD83D\uDDD1").queue(); + } catch (ErrorResponseException ignored) {} } } diff --git a/src/main/java/io/rixa/bot/commands/cmds/InfoCommand.java b/src/main/java/io/rixa/bot/commands/cmds/InfoCommand.java new file mode 100644 index 0000000..e3e4098 --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/InfoCommand.java @@ -0,0 +1,83 @@ +package io.rixa.bot.commands.cmds; + +import io.rixa.bot.Rixa; +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.DiscordUtils; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.JDAInfo; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.MessageEmbed; +import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +public class InfoCommand extends Command { + + public InfoCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(GuildMessageReceivedEvent event) { + System.out.println("INFO COMMAND TRIGGERED"); + String[] messages = event.getMessage().getContent().split(" "); + System.out.println(messages.length); + if(messages.length >= 2) { + Member member = DiscordUtils.memberSearch(event.getGuild(), event.getMessage().getContent(), false).get(0); + User user = member.getUser(); + OffsetDateTime time = user.getCreationTime(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM/dd/yyyy HH:mm:ss"); + MessageFactory.create("Playing **" + (member.getGame() == null ? "Unknown" : member.getGame().getName()) + "**") + .setColor(member.getColor()) + .setThumbnail(user.getAvatarUrl()) + .setAuthor("User Information: " + user.getName(), null, user.getAvatarUrl()) + .addField("User", user.getAsMention(), true) + .addField("ID", user.getId(), true) + .addField("Roles", String.valueOf(member.getRoles().size()), true) + .addField("Status", member.getOnlineStatus().name(), true) + .addField("Mutual Guilds", String.valueOf(user.getMutualGuilds().size()), true) + .addField("Nickname", member.getNickname() == null ? "None" : member.getNickname(), true) + .addField("Created", time.format(formatter), true) + .addField("Joined", member.getJoinDate().format(formatter), true) + .queue(event.getChannel()); + return; + } + User botOwner = event.getJDA().getUserById("202944101333729280"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss"); + Date date1 = new Date(Rixa.getTimeUp()); + long difference = new Date().getTime() - date1.getTime(); + long seconds = difference / 1000; + int day = (int) TimeUnit.SECONDS.toDays(seconds); + long hours = TimeUnit.SECONDS.toHours(seconds) - (day * 24); + long minute = TimeUnit.SECONDS.toMinutes(seconds) - (TimeUnit.SECONDS.toHours(seconds) * 60); + long second = TimeUnit.SECONDS.toSeconds(seconds) - (TimeUnit.SECONDS.toMinutes(seconds) * 60); + int guildCount = 0; + int userCount = 0; + for (JDA jda : Rixa.getInstance().getShardList()) { + guildCount += jda.getGuilds().size(); + userCount += jda.getUsers().size(); + } + String uptime = String.format("Uptime: %d days %d hours %d minutes %d seconds", day, hours, minute, second); + MessageFactory.create("Rixa is a user-friendly, multi-purpose bot currently in development which is capable of being customized to your Discord server needs. " + + "Rixa is complete with a dashboard, user profile, server statistics system, and many more features such as assigning roles on user join, music module, " + + "levels, and more. Rixa was created to bring ease and simplicity to managing Discord servers, and has since grown into much more than just a bot used for " + + "moderation.") + .setTitle("Rixa Discord Bot", "http://rixa.io/") + .addField("Created", event.getJDA().getSelfUser().getCreationTime().format(formatter), true) + .addField("Bot Uptime ", uptime, true) + .addField("Total Guilds", String.valueOf(guildCount), true) + .addField("Total Users", String.valueOf(userCount), true) + .addField("JDA Version", JDAInfo.VERSION, true) + .addField("Rixa Developer", botOwner.getName() + "#" + botOwner.getDiscriminator(), true) + .footer("Requested by " + event.getAuthor().getName() + "#" + event.getAuthor().getDiscriminator(), event.getAuthor().getAvatarUrl()) + .queue(event.getChannel()); + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/PingCommand.java b/src/main/java/io/rixa/bot/commands/cmds/PingCommand.java new file mode 100644 index 0000000..3de3a2a --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/PingCommand.java @@ -0,0 +1,18 @@ +package io.rixa.bot.commands.cmds; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; + +public class PingCommand extends Command { + + public PingCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(GuildMessageReceivedEvent event) { + MessageFactory.create("Pong! [" + event.getJDA().getPing() + "ms]").setColor(event.getMember().getColor()).queue(event.getChannel()); + } +} diff --git a/src/main/java/io/rixa/bot/commands/cmds/ServerInfoCommand.java b/src/main/java/io/rixa/bot/commands/cmds/ServerInfoCommand.java new file mode 100644 index 0000000..d374358 --- /dev/null +++ b/src/main/java/io/rixa/bot/commands/cmds/ServerInfoCommand.java @@ -0,0 +1,41 @@ +package io.rixa.bot.commands.cmds; + +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.perms.RixaPermission; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; + +import java.time.format.DateTimeFormatter; + +public class ServerInfoCommand extends Command { + + public ServerInfoCommand(String command, RixaPermission rixaPermission, String description) { + super(command, rixaPermission, description); + } + + @Override + public void execute(GuildMessageReceivedEvent event) { + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(event.getGuild()); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss"); + User owner = event.getGuild().getOwner().getUser(); + MessageFactory + .create(rixaGuild.getDescription()) + .setTitle(event.getGuild().getName(), String.format("http://rixa.io/servers/%s", event.getGuild().getId())) + .addField("Created", event.getGuild().getCreationTime().format(formatter), true) + .addField("Region", event.getGuild().getRegion().toString(), true) + .addField("Users", String.valueOf(event.getGuild().getMembers().size()), true) + .addField("Channel Categories", String.valueOf(event.getGuild().getCategories().size()), true) + .addField("Text Channels", String.valueOf(event.getGuild().getTextChannels().size()), true) + .addField("Voice Channels", String.valueOf(event.getGuild().getVoiceChannels().size()), true) + .addField("Verification Level", event.getGuild().getVerificationLevel().toString(), true) + .addField("Roles", String.valueOf(event.getGuild().getRoles().size()), true) + .addField("Owner", owner.getName() + "#" + owner.getDiscriminator(), true) + .addField("Enlisted", String.valueOf(true), true) + .setThumbnail(event.getGuild().getIconUrl()) + .footer("Server Id: " + event.getGuild().getId(), event.getGuild().getIconUrl()) + .queue(event.getChannel()); + } +} diff --git a/src/main/java/io/rixa/bot/commands/CommandHandler.java b/src/main/java/io/rixa/bot/commands/handler/CommandHandler.java similarity index 69% rename from src/main/java/io/rixa/bot/commands/CommandHandler.java rename to src/main/java/io/rixa/bot/commands/handler/CommandHandler.java index 025e9d1..1230350 100644 --- a/src/main/java/io/rixa/bot/commands/CommandHandler.java +++ b/src/main/java/io/rixa/bot/commands/handler/CommandHandler.java @@ -1,5 +1,6 @@ -package io.rixa.bot.commands; +package io.rixa.bot.commands.handler; +import io.rixa.bot.commands.Command; import io.rixa.bot.commands.exceptions.CommandNotFoundException; import java.util.HashMap; @@ -14,7 +15,14 @@ public class CommandHandler { commandMap.put(command.getCommand(), command); } + public void registerCommands(Command...commands) { + for (Command command : commands) { + registerCommand(command); + } + } + public Command getCommand(String commandName) throws CommandNotFoundException { + if (commandMap.containsKey(commandName)) return commandMap.get(commandName); for(Command command: commandMap.values()) { if (command.getAliases().contains(commandName)) { return command; diff --git a/src/main/java/io/rixa/bot/commands/RixaPermission.java b/src/main/java/io/rixa/bot/commands/perms/RixaPermission.java similarity index 56% rename from src/main/java/io/rixa/bot/commands/RixaPermission.java rename to src/main/java/io/rixa/bot/commands/perms/RixaPermission.java index bfb8f26..b00b2ea 100644 --- a/src/main/java/io/rixa/bot/commands/RixaPermission.java +++ b/src/main/java/io/rixa/bot/commands/perms/RixaPermission.java @@ -1,7 +1,18 @@ -package io.rixa.bot.commands; +package io.rixa.bot.commands.perms; public enum RixaPermission { - NONE; + NONE, + MUTE, + ADD_ROLE, + REMOVE_ROLE, + CLEAR_CHAT, + ACCESS_CONFIG, + PM_MESSAGE, + KICK_MEMBER, + BAN_MEMBER, + BATCH_MOVE, + UNMUTE, + TOGGLE_RAIDMODE; public static RixaPermission fromString(String string) { for (RixaPermission value : values()) { diff --git a/src/main/java/io/rixa/bot/data/storage/DatabaseAdapter.java b/src/main/java/io/rixa/bot/data/storage/DatabaseAdapter.java index ea0704c..5e7d3c3 100644 --- a/src/main/java/io/rixa/bot/data/storage/DatabaseAdapter.java +++ b/src/main/java/io/rixa/bot/data/storage/DatabaseAdapter.java @@ -2,9 +2,20 @@ package io.rixa.bot.data.storage; import io.rixa.bot.Rixa; import io.rixa.bot.data.config.Configuration; +import io.rixa.bot.data.storage.enums.Statements; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.jdbc.core.RowCountCallbackHandler; +import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.datasource.DriverManagerDataSource; +import java.sql.Array; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + public class DatabaseAdapter { private static DatabaseAdapter instance; @@ -22,9 +33,10 @@ public class DatabaseAdapter { Configuration config = rixaInstance.getConfiguration(); DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); - dataSource.setUrl( - String.format("jdbc:mysql://%s:%s/%s", config.getSqlCredentials().get("hostName"), - config.getSqlCredentials().get("port"), config.getSqlCredentials().get("databaseName"))); + String url = String.format("jdbc:mysql://%s:%s/%s", config.getSqlCredentials().get("hostName"), + config.getSqlCredentials().get("port"), config.getSqlCredentials().get("databaseName")); + System.out.println(url); + dataSource.setUrl(url); dataSource.setUsername(config.getSqlCredentials().get("userName")); dataSource.setPassword(config.getSqlCredentials().get("password")); jdbcTemplate = new JdbcTemplate(dataSource); @@ -36,8 +48,21 @@ public class DatabaseAdapter { } public boolean exists(String table, String key, String value) { - int amount = get().queryForObject(String.format("SELECT COUNT(*) FROM `%s` WHERE `%s` = ?", table, key), new Object[] { value }, Integer.class); - return amount > 0; + try { + int amount = get().queryForObject + (String.format(Statements.COUNT_CORE.getStatement(), table, key), new Object[]{value}, Integer.class); + return amount > 0; + } catch (EmptyResultDataAccessException ex) { + return false; + } + } + + public Array createArrayOf(String typeName, Object[] elements) { + try { + return get().getDataSource().getConnection().createArrayOf(typeName, elements); + } catch (SQLException ignored) { + } + return null; } public static DatabaseAdapter getInstance() { diff --git a/src/main/java/io/rixa/bot/data/storage/enums/Statements.java b/src/main/java/io/rixa/bot/data/storage/enums/Statements.java new file mode 100644 index 0000000..2de1ef0 --- /dev/null +++ b/src/main/java/io/rixa/bot/data/storage/enums/Statements.java @@ -0,0 +1,40 @@ +package io.rixa.bot.data.storage.enums; + +import lombok.Getter; + +public enum Statements { + + /* + Select statements + */ + SELECT_CORE("SELECT * FROM `core` WHERE `guild_id` = ?"), + SELECT_MODULE_STATUS("SELECT `{module_name}` FROM `modules` WHERE `guild_id` = ?"), + + + /* + Insert Statements + */ + INSERT_CORE("INSERT INTO `core` (`guild_id`, `guild_name`, `description`, `keywords`) VALUES (?, ?, ?, ?)"), + + /* + Count Statements + */ + COUNT_CORE("SELECT COUNT(*) FROM `%s` WHERE `%s` = ?"); + + /* + Delete Statements + */ + + + /* + Create Table Statements + */ + + @Getter private String statement; + public String getStatement(String key, String value) { + return getStatement().replace(key, value); + } + Statements(String s) { + this.statement = s; + } +} diff --git a/src/main/java/io/rixa/bot/events/BotJoinListener.java b/src/main/java/io/rixa/bot/events/BotJoinListener.java new file mode 100644 index 0000000..5606eac --- /dev/null +++ b/src/main/java/io/rixa/bot/events/BotJoinListener.java @@ -0,0 +1,14 @@ +package io.rixa.bot.events; + +import io.rixa.bot.guild.manager.GuildManager; +import net.dv8tion.jda.core.events.guild.GuildJoinEvent; +import net.dv8tion.jda.core.hooks.SubscribeEvent; + +public class BotJoinListener { + + @SubscribeEvent + public void onJoin(GuildJoinEvent event) { + System.out.println("GuildJoinEvent Event"); + event.getJDA().getGuilds().forEach(guild -> GuildManager.getInstance().addGuild(guild)); + } +} diff --git a/src/main/java/io/rixa/bot/events/MessageListener.java b/src/main/java/io/rixa/bot/events/MessageListener.java new file mode 100644 index 0000000..2531cf6 --- /dev/null +++ b/src/main/java/io/rixa/bot/events/MessageListener.java @@ -0,0 +1,48 @@ +package io.rixa.bot.events; + +import io.rixa.bot.Rixa; +import io.rixa.bot.commands.Command; +import io.rixa.bot.commands.exceptions.CommandNotFoundException; +import io.rixa.bot.guild.RixaGuild; +import io.rixa.bot.guild.manager.GuildManager; +import io.rixa.bot.guild.modules.module.ConversationModule; +import io.rixa.bot.utils.MessageFactory; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.events.ReadyEvent; +import net.dv8tion.jda.core.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.core.hooks.SubscribeEvent; + +public class MessageListener { + + @SubscribeEvent + public void onMessage(GuildMessageReceivedEvent event) { + System.out.println("GuildMessageReceivedEvent Event"); + String message = event.getMessage().getContent().trim(); + RixaGuild rixaGuild = GuildManager.getInstance().getGuild(event.getGuild()); + if (message.startsWith("@" + event.getGuild().getSelfMember().getEffectiveName())) { + chatter(rixaGuild, event.getChannel(), message.replace("@" + event.getGuild().getSelfMember().getEffectiveName(), "")); + return; + } + String prefix = "!"; + if (!(message.startsWith(prefix))) return; + String commandName = (message.contains(" ") ? message.split(" ")[0] : message); + command(commandName, prefix, event); + } + + private void command(String commandName, String prefix, GuildMessageReceivedEvent event) { + commandName = commandName.replaceFirst(prefix, ""); + try { + Command command = Rixa.getInstance().getCommandHandler().getCommand(commandName); + command.execute(event); + } catch (CommandNotFoundException ignored) {} + } + + private void chatter(RixaGuild rixaGuild, TextChannel channel, String message) { + ConversationModule conversationModule = (ConversationModule) rixaGuild.getModule("Conversation"); + if (!conversationModule.isEnabled()) return; + try { + MessageFactory.create(conversationModule.getChatBotSession().think(message)).selfDestruct(0) + .queue(channel); + } catch (Exception ignored) {} + } +} diff --git a/src/main/java/io/rixa/bot/events/ReadyListener.java b/src/main/java/io/rixa/bot/events/ReadyListener.java index 2ed6f31..af3c21c 100644 --- a/src/main/java/io/rixa/bot/events/ReadyListener.java +++ b/src/main/java/io/rixa/bot/events/ReadyListener.java @@ -8,6 +8,10 @@ public class ReadyListener { @SubscribeEvent public void onReady(ReadyEvent event) { - event.getJDA().getGuilds().forEach(guild -> GuildManager.getInstance().addGuild(guild)); + if (event.getJDA().getGuilds().size() == 0) return; + System.out.println("Ready Event Triggered"); + event.getJDA().getGuilds().forEach(guild -> { + GuildManager.getInstance().addGuild(guild); + }); } } diff --git a/src/main/java/io/rixa/bot/guild/RixaGuild.java b/src/main/java/io/rixa/bot/guild/RixaGuild.java index a85105a..3caa144 100644 --- a/src/main/java/io/rixa/bot/guild/RixaGuild.java +++ b/src/main/java/io/rixa/bot/guild/RixaGuild.java @@ -1,7 +1,9 @@ package io.rixa.bot.guild; +import io.rixa.bot.Rixa; import io.rixa.bot.guild.manager.IGuild; import io.rixa.bot.guild.modules.RixaModule; +import io.rixa.bot.guild.modules.module.ConversationModule; import lombok.Getter; import lombok.Setter; import net.dv8tion.jda.core.entities.Guild; @@ -28,7 +30,9 @@ public class RixaGuild implements IGuild { } @Override - public void load() {} + public void load() { + registerModule(new ConversationModule("Conversation", "Have a conversation with Rixa!")); + } @Override public void save() { } @@ -39,8 +43,8 @@ public class RixaGuild implements IGuild { } @Override - public RixaModule registerModule(String id, RixaModule module) { - if (!(isRegistered(id))) modules.put(id, module); + public RixaModule registerModule(RixaModule module) { + if (!(isRegistered(module.getName()))) modules.put(module.getName(), module); return module; } diff --git a/src/main/java/io/rixa/bot/guild/manager/GuildManager.java b/src/main/java/io/rixa/bot/guild/manager/GuildManager.java index d28a203..a588266 100644 --- a/src/main/java/io/rixa/bot/guild/manager/GuildManager.java +++ b/src/main/java/io/rixa/bot/guild/manager/GuildManager.java @@ -1,6 +1,7 @@ package io.rixa.bot.guild.manager; import io.rixa.bot.data.storage.DatabaseAdapter; +import io.rixa.bot.data.storage.enums.Statements; import io.rixa.bot.guild.RixaGuild; import net.dv8tion.jda.core.entities.Guild; @@ -20,18 +21,35 @@ public class GuildManager { return (instance == null) ? new GuildManager() : instance; } - public void addGuild(Guild guild) { + public RixaGuild getGuild(Guild guild) { + if (!hasGuild(guild.getId())) { + return addGuild(guild); + } + return rixaGuildMap.get(guild.getId()); + } + + public RixaGuild getGuild(String id) { + return rixaGuildMap.get(id); + } + + public boolean hasGuild(String id) { + return rixaGuildMap.containsKey(id); + } + + public RixaGuild addGuild(Guild guild) { if (!(DatabaseAdapter.getInstance().exists("core", "guild_id", guild.getId()))) { insert(guild); } - RixaGuild rixaGuild = (RixaGuild) DatabaseAdapter.getInstance().get().queryForObject( - "SELECT * FROM `core` WHERE `guild_name` = ?", new Object[] { guild.getId() }, new GuildMapper()); + RixaGuild rixaGuild = new RixaGuild(guild); rixaGuildMap.put(guild.getId(), rixaGuild); + DatabaseAdapter.getInstance().get().queryForObject( + Statements.SELECT_CORE.getStatement(), new Object[] { guild.getId() }, new GuildMapper()); + return rixaGuild; } private void insert(Guild guild) { DatabaseAdapter.getInstance().get().update - ("INSERT INTO `core` (`guild_id`, `guild_name`, `description`, `keywords`) VALUES (?, ?, ?, ?)", - guild.getId(), guild.getName(), "Description not set.", "No Keywords Found."); + (Statements.INSERT_CORE.getStatement(), + guild.getId(), guild.getName(), "Description not set.", "No Keywords Found "); } } diff --git a/src/main/java/io/rixa/bot/guild/manager/GuildMapper.java b/src/main/java/io/rixa/bot/guild/manager/GuildMapper.java index 1fe5212..222513c 100644 --- a/src/main/java/io/rixa/bot/guild/manager/GuildMapper.java +++ b/src/main/java/io/rixa/bot/guild/manager/GuildMapper.java @@ -1,22 +1,27 @@ package io.rixa.bot.guild.manager; -import io.rixa.bot.guild.RixaGuild; import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; +import java.util.Collections; import java.util.List; public class GuildMapper implements RowMapper { @Override public IGuild mapRow(ResultSet resultSet, int i) throws SQLException { - IGuild guild = new RixaGuild(null); - guild.setDescription(resultSet.getString("description")); - List keywords = Arrays.asList((String[])resultSet.getArray("keywords").getArray()); + IGuild guild = GuildManager.getInstance().getGuild(resultSet.getString("guild_id")); + /*System.out.println("Keywords: " + resultSet.getArray("keywords")); + System.out.println("Keywords 2: " + resultSet.getArray("keywords").getArray());*/ + String description = resultSet.getString("description"); + String keyWords = resultSet.getString("keywords"); + List keywords = (!keyWords.contains(",") || + keyWords.equalsIgnoreCase("No keywords found")) ? Collections.singletonList(keyWords) : + Arrays.asList(keyWords.split(":")); + guild.setDescription(description); guild.setKeywords(keywords); - // Register guild; return guild; } } diff --git a/src/main/java/io/rixa/bot/guild/manager/IGuild.java b/src/main/java/io/rixa/bot/guild/manager/IGuild.java index 9d41392..351766c 100644 --- a/src/main/java/io/rixa/bot/guild/manager/IGuild.java +++ b/src/main/java/io/rixa/bot/guild/manager/IGuild.java @@ -10,7 +10,7 @@ public interface IGuild { void load(); void save(); RixaModule getModule(String id); - RixaModule registerModule(String id, RixaModule module); + RixaModule registerModule(RixaModule module); boolean isRegistered(String id); void setDescription(String description); void setKeywords(List keywords); diff --git a/src/main/java/io/rixa/bot/guild/modules/RixaModule.java b/src/main/java/io/rixa/bot/guild/modules/RixaModule.java index 18f331b..9efdd94 100644 --- a/src/main/java/io/rixa/bot/guild/modules/RixaModule.java +++ b/src/main/java/io/rixa/bot/guild/modules/RixaModule.java @@ -4,6 +4,8 @@ public interface RixaModule { String getName(); String getDescription(); + boolean isEnabled(); void load(); void save(); + void reload(); } diff --git a/src/main/java/io/rixa/bot/guild/modules/module/ConversationModule.java b/src/main/java/io/rixa/bot/guild/modules/module/ConversationModule.java new file mode 100644 index 0000000..2144c26 --- /dev/null +++ b/src/main/java/io/rixa/bot/guild/modules/module/ConversationModule.java @@ -0,0 +1,51 @@ +package io.rixa.bot.guild.modules.module; + +import com.google.code.chatterbotapi.ChatterBot; +import com.google.code.chatterbotapi.ChatterBotFactory; +import com.google.code.chatterbotapi.ChatterBotSession; +import com.google.code.chatterbotapi.ChatterBotType; +import io.rixa.bot.data.storage.DatabaseAdapter; +import io.rixa.bot.data.storage.enums.Statements; +import io.rixa.bot.guild.modules.RixaModule; +import lombok.Getter; +import lombok.Setter; + +public class ConversationModule implements RixaModule { + + @Getter private ChatterBotFactory factory; + @Getter private ChatterBotSession chatBotSession; + @Getter private ChatterBot chatBot; + @Getter private String name, description; + @Getter @Setter boolean enabled; + + public ConversationModule(String name, String description) { + this.name = name; + this.description = description; + this.enabled = true; + } + + @Override + public void load() { + setEnabled(DatabaseAdapter.getInstance().get().queryForObject + (Statements.SELECT_MODULE_STATUS.getStatement("{module_name}", getName()), + new Object[]{name}, (resultSet, i) -> resultSet.getBoolean("enabled"))); + reload(); + } + + @Override + public void save() { + // Check & Set if enabled; + } + + @Override + public void reload() { + if (!isEnabled()) return; + try { + factory = new ChatterBotFactory(); + chatBot = factory.create(ChatterBotType.PANDORABOTS, "b0dafd24ee35a477"); + chatBotSession = chatBot.createSession(); + } catch(Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/io/rixa/bot/guild/modules/module/LevelsModule.java b/src/main/java/io/rixa/bot/guild/modules/module/LevelsModule.java index 2ab140e..b7c8981 100644 --- a/src/main/java/io/rixa/bot/guild/modules/module/LevelsModule.java +++ b/src/main/java/io/rixa/bot/guild/modules/module/LevelsModule.java @@ -6,11 +6,12 @@ import lombok.Setter; public class LevelsModule implements RixaModule { - @Getter @Setter private String name, description; + @Getter private String name, description; + @Getter @Setter boolean enabled; public LevelsModule(String name, String description) { - setName(name); - setDescription(description); + this.name = name; + this.description = description; } @Override @@ -22,4 +23,9 @@ public class LevelsModule implements RixaModule { public void save() { } + + @Override + public void reload() { + + } } diff --git a/src/main/java/io/rixa/bot/utils/DiscordUtils.java b/src/main/java/io/rixa/bot/utils/DiscordUtils.java new file mode 100644 index 0000000..62b95ef --- /dev/null +++ b/src/main/java/io/rixa/bot/utils/DiscordUtils.java @@ -0,0 +1,54 @@ +package io.rixa.bot.utils; + +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.Member; +import net.dv8tion.jda.core.entities.Role; + +import java.util.ArrayList; +import java.util.List; + +public class DiscordUtils { + + public static boolean isInt(String s) { + try { + Integer.parseInt(s); + return true; + } catch (NumberFormatException ex) { + return false; + } + } + + public static List memberSearch(Guild guild, String string, boolean bots) { + List members = new ArrayList<>(); + String finalString = string.toLowerCase(); + for (Member member : guild.getMembers()) { + if ((member.getUser().getName().toLowerCase() + "#" + member.getUser().getDiscriminator()).contains(finalString) + || (member.getEffectiveName().toLowerCase().contains(finalString)) + || finalString.contains(member.getUser().getId()) + || finalString.contains(member.getUser().getName().toLowerCase() + "#" + member.getUser().getDiscriminator()) + || finalString.contains(member.getEffectiveName().toLowerCase()) + || finalString.contains(member.getUser().getName().toLowerCase()) + || finalString.equalsIgnoreCase(member.getEffectiveName().toLowerCase()) + || finalString.equalsIgnoreCase(member.getUser().getName().toLowerCase()) + ) { + + if (!bots && member.getUser().isBot()) continue; + members.add(member); + } + } + + return members; + } + + public static List roleSearch(Guild guild, String string) { + List roles = new ArrayList<>(); + guild.getRoles().forEach(role -> { + if (role.getName().toLowerCase().contains(string.toLowerCase()) + || string.contains(role.getId()) + || string.toLowerCase().contains(role.getName().toLowerCase()) + ) + roles.add(role); + }); + return roles; + } +} diff --git a/src/main/java/io/rixa/bot/utils/MessageFactory.java b/src/main/java/io/rixa/bot/utils/MessageFactory.java new file mode 100644 index 0000000..0f8215b --- /dev/null +++ b/src/main/java/io/rixa/bot/utils/MessageFactory.java @@ -0,0 +1,146 @@ +package io.rixa.bot.utils; + +import lombok.Getter; +import net.dv8tion.jda.core.EmbedBuilder; +import net.dv8tion.jda.core.entities.Message; +import net.dv8tion.jda.core.entities.MessageEmbed; +import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.exceptions.PermissionException; +import net.dv8tion.jda.core.exceptions.RateLimitedException; + +import java.awt.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class MessageFactory { + + private Message message; + + @Getter + private EmbedBuilder builder; + @Getter private int selfDestruct; + + public MessageFactory(String description) { + this(); + setDescription(description); + } + + public MessageFactory() { + this.builder = new EmbedBuilder(); + selfDestruct = 20; + } + + public MessageFactory setTitle(String title, String url) { + builder.setTitle(title, url); + return this; + } + + public MessageFactory setDescription(String description) { + builder.setDescription(description); + return this; + } + + public MessageFactory setTitle(String title) { + builder.setTitle(title); + return this; + } + + public MessageFactory setColor(Color color) { + builder.setColor(color); + return this; + } + + public MessageFactory addField(String name, String value, boolean inLine) { + builder.addField(name, value, inLine); + return this; + } + + public MessageFactory addThumbnail(String url) { + builder.setThumbnail(url); + return this; + } + + public MessageFactory setAuthor(String name, String url, String iconURL) { + builder.setAuthor(name, url, iconURL); + return this; + } + + public void queue(TextChannel channel) { + try { + message = channel.sendMessage(builder.build()).complete(true); + destroy(); + } catch (PermissionException ex) { + System.out.println("I do not have permission: " + ex.getPermission().getName() + " on server " + channel.getGuild().getName() + " in channel: " + channel.getName()); + } catch (RateLimitedException e) { + e.printStackTrace(); + } + } + + public Message complete(TextChannel channel) { + try { + message = channel.sendMessage(builder.build()).complete(); + destroy(); + return message; + } catch (PermissionException ex) { + System.out.println("I do not have permission: " + ex.getPermission().getName() + " on server " + channel.getGuild().getName() + " in channel: " + channel.getName()); + return null; + } + } + + public void send(User member) { + member.openPrivateChannel().complete().sendMessage(builder.build()).queue(); + destroy(); + } + + public MessageFactory sendUser(User member) { + this.message = member.openPrivateChannel().complete().sendMessage(builder.build()).complete(); + destroy(); + return this; + } + + public MessageFactory addReaction(String reaction) { + if(message == null) { + throw new NullPointerException("Message must not be null!"); + } + message.addReaction(reaction).complete(); + return this; + } + + public MessageFactory selfDestruct(int time) { + this.selfDestruct = time; + return this; + } + + private void destroy() { + if (getSelfDestruct() == 0) return; + ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + executor.schedule(() -> { + if (message != null) message.delete().queue(); + executor.shutdown(); + }, getSelfDestruct(), TimeUnit.SECONDS); + } + + public MessageEmbed build() { + return builder.build(); + } + + public MessageFactory setThumbnail(String thumbnail) { + builder.setThumbnail(thumbnail); + return this; + } + + public MessageFactory footer(String s, String iconURL) { + builder.setFooter(s, iconURL); + return this; + } + + public static MessageFactory create() { + return new MessageFactory(); + } + + public static MessageFactory create(String s) { + return new MessageFactory(s); + } +} \ No newline at end of file