diff --git a/.gitignore b/.gitignore index 3de8538..cd87923 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ out/ -target/ .idea/ classes/ +target/ discordwhitelister.iml *.iml +.attach_pid* +dependency-reduced-pom.xml diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml deleted file mode 100644 index d638c32..0000000 --- a/dependency-reduced-pom.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - 4.0.0 - uk.co.angrybee.joe - discord-whitelister - discord-whitelister - 1.3.8 - https://github.com/JoeShimell/DiscordWhitelisterSpigot - - - - - maven-clean-plugin - 3.1.0 - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - maven-shade-plugin - - - package - - shade - - - - - ${project.artifactId}-${project.version} - true - - - - - maven-antrun-plugin - 1.8 - - - install - - run - - - - - - - - - - - - - - maven-compiler-plugin - - 8 - 8 - - - - maven-shade-plugin - 3.2.4 - - - - - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - - false - - bintray-dv8fromtheworld-maven - bintray - https://dl.bintray.com/dv8fromtheworld/maven - - - - - org.spigotmc - spigot-api - 1.16.3-R0.1-SNAPSHOT - provided - - - - 1.8 - UTF-8 - 1.8 - - diff --git a/pom.xml b/pom.xml index fbd0dab..ff88764 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ uk.co.angrybee.joe discord-whitelister - 1.3.8 + 1.4.0 discord-whitelister https://github.com/JoeShimell/DiscordWhitelisterSpigot @@ -22,6 +22,7 @@ spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + false @@ -40,6 +41,7 @@ 1.16.3-R0.1-SNAPSHOT provided + net.dv8tion JDA @@ -51,76 +53,94 @@ + com.googlecode.json-simple json-simple 1.1.1 + org.apache.logging.log4j log4j-api - 2.12.1 + 2.13.3 + org.apache.logging.log4j log4j-core - 2.13.2 + 2.13.3 + org.apache.logging.log4j log4j-slf4j-impl - 2.12.1 + 2.13.3 - + + + org.yaml + snakeyaml + 1.26 + + org.apache.maven.plugins maven-shade-plugin 3.2.4 + maven-plugin - + - maven-clean-plugin 3.1.0 - + maven-resources-plugin 3.0.2 + maven-compiler-plugin 3.8.0 + maven-surefire-plugin 2.22.1 + maven-jar-plugin 3.0.2 + maven-install-plugin 2.5.2 + maven-deploy-plugin 2.8.2 - + + maven-site-plugin 3.7.1 + maven-project-info-reports-plugin 3.0.0 + org.apache.maven.plugins maven-shade-plugin @@ -146,7 +166,7 @@ 1.8 - install + test run @@ -159,8 +179,8 @@ - + org.apache.maven.plugins @@ -177,5 +197,6 @@ 3.2.4 + diff --git a/src/main/java/uk/co/angrybee/joe/AuthorPermissions.java b/src/main/java/uk/co/angrybee/joe/AuthorPermissions.java index 8d4ea94..1a6d01b 100644 --- a/src/main/java/uk/co/angrybee/joe/AuthorPermissions.java +++ b/src/main/java/uk/co/angrybee/joe/AuthorPermissions.java @@ -5,10 +5,13 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import java.util.Arrays; -public class AuthorPermissions { +public class AuthorPermissions +{ private boolean userCanAddRemove = false; private boolean userCanAdd = false; private boolean userHasLimitedAdd = false; + private boolean userIsBanned = false; + private boolean userCanUseClear = false; public boolean isUserCanAddRemove() { return userCanAddRemove; @@ -27,8 +30,13 @@ public class AuthorPermissions { return userCanAdd || userCanAddRemove || userHasLimitedAdd; } + public boolean isUserIsBanned() { return userIsBanned; } + + public boolean isUserCanUseClear() { return userCanUseClear; } + public AuthorPermissions(MessageReceivedEvent event) { + // TODO: merge these all together? why calling more times than needed for (Role role : event.getGuild().getMember(event.getAuthor()).getRoles()) { if(!DiscordWhitelister.useIdForRoles) @@ -88,5 +96,48 @@ public class AuthorPermissions { } } } + + if(DiscordWhitelister.useOnBanEvents) + { + for(Role role : event.getGuild().getMember(event.getAuthor()).getRoles()) + { + if(!DiscordWhitelister.useIdForRoles) + { + if (Arrays.stream(DiscordWhitelister.bannedRoles).parallel().anyMatch(role.getName()::equalsIgnoreCase)) + { + userIsBanned = true; + break; + } + } + else + { + if (Arrays.stream(DiscordWhitelister.bannedRoles).parallel().anyMatch(role.getId()::equalsIgnoreCase)) + { + userIsBanned = true; + break; + } + } + } + } + + for(Role role : event.getGuild().getMember(event.getAuthor()).getRoles()) + { + if(!DiscordWhitelister.useIdForRoles) + { + if(Arrays.stream(DiscordClient.allowedToClearNamesRoles).parallel().anyMatch(role.getName()::equalsIgnoreCase)) + { + userCanUseClear = true; + break; + } + } + else + { + if(Arrays.stream(DiscordClient.allowedToClearNamesRoles).parallel().anyMatch(role.getId()::equalsIgnoreCase)) + { + userCanUseClear = true; + break; + } + } + } } } diff --git a/src/main/java/uk/co/angrybee/joe/CheckIntents.java b/src/main/java/uk/co/angrybee/joe/CheckIntents.java deleted file mode 100644 index 92c874a..0000000 --- a/src/main/java/uk/co/angrybee/joe/CheckIntents.java +++ /dev/null @@ -1,40 +0,0 @@ -package uk.co.angrybee.joe; - -import net.dv8tion.jda.api.events.DisconnectEvent; -import net.dv8tion.jda.api.events.ShutdownEvent; -import net.dv8tion.jda.api.hooks.ListenerAdapter; -import net.dv8tion.jda.api.requests.CloseCode; -import net.dv8tion.jda.api.requests.GatewayIntent; -import org.bukkit.Bukkit; - -import java.util.List; - -// Check for privileged intents on disconnect -public class CheckIntents extends ListenerAdapter -{ - @Override - public void onShutdown(ShutdownEvent shutdownEvent) - { - CheckIntents(shutdownEvent.getCloseCode()); - } - - @Override - public void onDisconnect(DisconnectEvent disconnectEvent) - { - CheckIntents(disconnectEvent.getCloseCode()); - } - - private void CheckIntents(CloseCode closeCode) - { - if(closeCode == null) - return; - - if(closeCode == CloseCode.DISALLOWED_INTENTS) - { - DiscordClient.ShutdownClient(); - - DiscordWhitelister.getPluginLogger().severe("[DiscordWhitelister] Cannot connect as this bot is not eligible to request the privileged intent 'GUILD_MEMBERS'"); - DiscordWhitelister.getPluginLogger().severe("[DiscordWhitelister] To correct this please go to your bot located at: https://discord.com/developers/applications and enable 'Server Members Intent'"); - } - } -} diff --git a/src/main/java/uk/co/angrybee/joe/Configs/CustomMessagesConfig.java b/src/main/java/uk/co/angrybee/joe/Configs/CustomMessagesConfig.java index b67ab40..63b4b64 100644 --- a/src/main/java/uk/co/angrybee/joe/Configs/CustomMessagesConfig.java +++ b/src/main/java/uk/co/angrybee/joe/Configs/CustomMessagesConfig.java @@ -89,6 +89,9 @@ public class CustomMessagesConfig CheckEntry("user-was-removed-title", "This user was previously removed by a staff member"); CheckEntry("user-was-removed", "{Sender}, this user was previously removed by a staff member ({StaffMember}). Please ask a user with higher permissions to add this user."); + CheckEntry("user-was-removed-in-game-title", "This user was previously removed by a staff member"); + CheckEntry("user-was-removed-in-game", "{Sender}, this user was previously removed by a staff member in-game ({StaffMember}). Please ask a user with higher permissions to add this user."); + CheckEntry("whitelists-remaining-title", "Whitelists Remaining"); CheckEntry("whitelists-remaining", "You have **{RemainingWhitelists} out of {MaxWhitelistAmount}** whitelists remaining."); @@ -103,6 +106,24 @@ public class CustomMessagesConfig CheckEntry("remove-success-title", "{MinecraftUsername} has been removed"); CheckEntry("remove-success", "{Sender} has removed {MinecraftUsername} from the whitelist"); + + CheckEntry("banned-title", "You have been banned!"); + CheckEntry("banned-message", "{Sender}, you cannot use this bot as you have been banned!"); + + CheckEntry("clear-name-success-title", "Successfully Cleared `{MinecraftUsername}`"); + CheckEntry("clear-name-success-message", "{Sender} successfully cleared username `{MinecraftUsername}` from {DiscordID}'s whitelisted users."); + + CheckEntry("clear-name-failure-title", "{MinecraftUsername} not Found"); + CheckEntry("clear-name-failure-message", "{Sender}, could not find name `{MinecraftUsername}` to clear in user list."); + + CheckEntry("clear-ban-success-title", "Successfully Cleared `{MinecraftUsername}`"); + CheckEntry("clear-ban-success-message", "{Sender} has successfully cleared `{MinecraftUsername}` from the removed list(s)."); + + CheckEntry("clear-ban-failure-title", "Failed to clear `{MinecraftUsername}`"); + CheckEntry("clear-ban-failure-message", "{Sender}, `{MinecraftUsername}` cannot be found in any of the removed lists!"); + + CheckEntry("instructional-message-title", "How to Whitelist"); + CheckEntry("instructional-message", "Use `!whitelist add ` to whitelist yourself. In the case of whitelisting an incorrect name, please contact a staff member to clear it from the whitelist."); } } diff --git a/src/main/java/uk/co/angrybee/joe/Configs/CustomPrefixConfig.java b/src/main/java/uk/co/angrybee/joe/Configs/CustomPrefixConfig.java index 45f7f3b..3023d8e 100644 --- a/src/main/java/uk/co/angrybee/joe/Configs/CustomPrefixConfig.java +++ b/src/main/java/uk/co/angrybee/joe/Configs/CustomPrefixConfig.java @@ -65,6 +65,10 @@ public class CustomPrefixConfig CheckEntry("whitelist-add-prefix", "!whitelist add"); CheckEntry("whitelist-remove-prefix", "!whitelist remove"); + + CheckEntry("clear-name-prefix", "!clearname"); + + CheckEntry("clear-ban-prefix", "!clearban"); } } diff --git a/src/main/java/uk/co/angrybee/joe/Configs/MainConfig.java b/src/main/java/uk/co/angrybee/joe/Configs/MainConfig.java index 89f97b1..2060b3d 100644 --- a/src/main/java/uk/co/angrybee/joe/Configs/MainConfig.java +++ b/src/main/java/uk/co/angrybee/joe/Configs/MainConfig.java @@ -86,6 +86,11 @@ public class MainConfig // The roles to add/remove when whitelisted/removed CheckEntry("whitelisted-roles", Collections.singletonList("Whitelisted")); + CheckEntry("banned-roles", Collections.singletonList("Banned")); + + // For clear name & ban commands + CheckEntry("clear-command-roles", Collections.singletonList("Admin")); + CheckEntry("target-text-channels", Arrays.asList("000000000000000000", "111111111111111111")); // EasyWhitelist support (https://www.spigotmc.org/resources/easywhitelist-name-based-whitelist.65222/) @@ -100,6 +105,11 @@ public class MainConfig // If the limited whitelist feature should be enabled CheckEntry("limited-whitelist-enabled", true); + // Remove whitelisted role, assign to banned role, remove their whitelisted players + CheckEntry("use-on-ban-events", false); + + CheckEntry("unwhitelist-and-clear-perms-on-name-clear", true); + // The amount of times a non-staff user is allowed to whitelist CheckEntry("max-whitelist-amount", 3); @@ -107,6 +117,8 @@ public class MainConfig CheckEntry("removed-list-enabled", true); + CheckEntry("add-in-game-adds-and-removes-to-list", true); + CheckEntry("use-custom-messages", false); CheckEntry("use-custom-prefixes", false); @@ -117,6 +129,18 @@ public class MainConfig CheckEntry("show-vanished-players-in-player-count", false); + CheckEntry("assign-perms-with-ultra-perms", false); + + CheckEntry("use-on-whitelist-commands", false); + + CheckEntry("send-instructional-message-on-whitelist", false); + + CheckEntry("use-timer-for-instructional-message", false); + + CheckEntry("timer-wait-time-in-seconds", 5); + + CheckEntry("un-whitelist-on-server-leave", true); + // Remove old role entry if found, move role to new array (for people with v1.3.6 or below) if(whitelisterBotConfig.get("whitelisted-role") != null) { diff --git a/src/main/java/uk/co/angrybee/joe/Configs/OnWhitelistCommandsConfig.java b/src/main/java/uk/co/angrybee/joe/Configs/OnWhitelistCommandsConfig.java new file mode 100644 index 0000000..d771efd --- /dev/null +++ b/src/main/java/uk/co/angrybee/joe/Configs/OnWhitelistCommandsConfig.java @@ -0,0 +1,114 @@ +package uk.co.angrybee.joe.Configs; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import uk.co.angrybee.joe.DiscordWhitelister; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; + +public class OnWhitelistCommandsConfig +{ + private static File onWhitelistCommandsConfigFile; + private static FileConfiguration onWhitelistCommandsConfig; + + public static FileConfiguration getPermissionsConfig() { return onWhitelistCommandsConfig; } + + private static boolean onWhitelistCommandsFileCreated = false; + + public static void ConfigSetup() + { + onWhitelistCommandsConfigFile = new File(DiscordWhitelister.getPlugin().getDataFolder(), "on-whitelist-commands.yml"); + onWhitelistCommandsConfig = new YamlConfiguration(); + + if(!onWhitelistCommandsConfigFile.exists()) + CreateConfig(); + + LoadConfigFile(); + CheckEntries(); + SaveConfig(); + } + + private static void CreateConfig() + { + try + { + onWhitelistCommandsConfigFile.createNewFile(); + } + catch (IOException e) + { + e.printStackTrace(); + } + + DiscordWhitelister.getPluginLogger().info("on whitelist commands file created at: " + onWhitelistCommandsConfigFile.getPath()); + onWhitelistCommandsFileCreated = true; + } + + private static void LoadConfigFile() + { + try + { + onWhitelistCommandsConfig.load(onWhitelistCommandsConfigFile); + } + catch (IOException | InvalidConfigurationException e) + { + e.printStackTrace(); + } + } + + private static void CheckEntries() + { + if(onWhitelistCommandsConfigFile.exists()) + { + // Write comments + if(onWhitelistCommandsFileCreated) + { + SaveConfig(); // save and load again + try + { + FileWriter fileWriter = new FileWriter(onWhitelistCommandsConfigFile); + fileWriter.write("# The list of commands that will be dispatched when a player gets whitelisted. (Use the following syntax: \n" + + "# \"%TYPE%:%COMMAND%\", being %TYPE% whether 'CONSOLE' or 'PLAYER' and the command without the slash (/)\n" + + "# placeholder %PLAYER% is supported here).\n" + + "# NOTE: The 'PLAYER' type will only work if the target whitelisted player is in the server at the time of command dispatch."); + + fileWriter.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + LoadConfigFile(); + } + + CheckEntry("on-whitelist-commands", Arrays.asList("CONSOLE:gamemode adventure %PLAYER%", "CONSOLE:say hello testing")); + } + } + + private static void SaveConfig() + { + try + { + onWhitelistCommandsConfig.save(onWhitelistCommandsConfigFile.getPath()); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private static void CheckEntry(String entryName, Object passedValue) + { + if(onWhitelistCommandsConfig.get(entryName) == null) + { + onWhitelistCommandsConfig.set(entryName, passedValue); + + if(!onWhitelistCommandsFileCreated) + DiscordWhitelister.getPluginLogger().warning("Entry '" + entryName + "' was not found, adding it to on-whitelist-permissions.yml..."); + } + } +} diff --git a/src/main/java/uk/co/angrybee/joe/Configs/PermissionsConfig.java b/src/main/java/uk/co/angrybee/joe/Configs/PermissionsConfig.java new file mode 100644 index 0000000..acd2fe6 --- /dev/null +++ b/src/main/java/uk/co/angrybee/joe/Configs/PermissionsConfig.java @@ -0,0 +1,92 @@ +package uk.co.angrybee.joe.Configs; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import uk.co.angrybee.joe.DiscordWhitelister; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; + +public class PermissionsConfig +{ + private static File permissionsConfigFile; + private static FileConfiguration permissionsConfig; + + public static FileConfiguration getPermissionsConfig() { return permissionsConfig; } + + private static boolean permissionsFileCreated = false; + + public static void ConfigSetup() + { + permissionsConfigFile = new File(DiscordWhitelister.getPlugin().getDataFolder(), "on-whitelist-permissions.yml"); + permissionsConfig = new YamlConfiguration(); + + if(!permissionsConfigFile.exists()) + CreateConfig(); + + LoadConfigFile(); + CheckEntries(); + SaveConfig(); + } + + private static void CreateConfig() + { + try + { + permissionsConfigFile.createNewFile(); + } + catch (IOException e) + { + e.printStackTrace(); + } + + DiscordWhitelister.getPluginLogger().info("on whitelist permissions file created at: " + permissionsConfigFile.getPath()); + permissionsFileCreated = true; + } + + private static void LoadConfigFile() + { + try + { + permissionsConfig.load(permissionsConfigFile); + } + catch (IOException | InvalidConfigurationException e) + { + e.printStackTrace(); + } + } + + private static void CheckEntries() + { + if(permissionsConfigFile.exists()) + { + // test permission + CheckEntry("perms-on-whitelist", Collections.singletonList("bukkit.command.tps")); + } + } + + private static void SaveConfig() + { + try + { + permissionsConfig.save(permissionsConfigFile.getPath()); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private static void CheckEntry(String entryName, Object passedValue) + { + if(permissionsConfig.get(entryName) == null) + { + permissionsConfig.set(entryName, passedValue); + + if(!permissionsFileCreated) + DiscordWhitelister.getPluginLogger().warning("Entry '" + entryName + "' was not found, adding it to on-whitelist-permissions.yml..."); + } + } +} diff --git a/src/main/java/uk/co/angrybee/joe/DiscordClient.java b/src/main/java/uk/co/angrybee/joe/DiscordClient.java index 5c7f949..56ef0af 100644 --- a/src/main/java/uk/co/angrybee/joe/DiscordClient.java +++ b/src/main/java/uk/co/angrybee/joe/DiscordClient.java @@ -1,24 +1,25 @@ package uk.co.angrybee.joe; -import net.dv8tion.jda.api.AccountType; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.*; -import net.dv8tion.jda.api.events.guild.member.GuildMemberLeaveEvent; +import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.requests.GatewayIntent; -import net.dv8tion.jda.internal.utils.PermissionUtil; -import org.bukkit.configuration.InvalidConfigurationException; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.json.simple.JSONArray; +import net.dv8tion.jda.api.utils.MemberCachePolicy; +import net.dv8tion.jda.api.utils.cache.CacheFlag; import org.json.simple.JSONObject; import org.json.simple.JSONValue; -import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; -import uk.co.angrybee.joe.Configs.CustomPrefixConfig; +import org.yaml.snakeyaml.Yaml; +import uk.co.angrybee.joe.Configs.*; +import uk.co.angrybee.joe.Events.ShutdownEvents; +import uk.co.angrybee.joe.Stores.InGameRemovedList; +import uk.co.angrybee.joe.Stores.RemovedList; +import uk.co.angrybee.joe.Stores.UserList; +import uk.co.angrybee.joe.Stores.WhitelistedPlayers; import javax.annotation.Nonnull; import javax.security.auth.login.LoginException; @@ -26,6 +27,8 @@ import java.awt.Color; import java.io.*; import java.net.URL; import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; // handles Discord interaction public class DiscordClient extends ListenerAdapter @@ -33,11 +36,14 @@ public class DiscordClient extends ListenerAdapter public static String[] allowedToAddRemoveRoles; public static String[] allowedToAddRoles; public static String[] allowedToAddLimitedRoles; + public static String[] allowedToClearNamesRoles; private static String[] targetTextChannels; public static String whitelistAddPrefix; public static String whitelistRemovePrefix; + public static String clearNamePrefix; + public static String clearBanPrefix; private static MessageEmbed botInfo; private static MessageEmbed addCommandInfo; @@ -50,12 +56,12 @@ public class DiscordClient extends ListenerAdapter private static boolean whitelistedRoleAutoAdd; private static boolean whitelistedRoleAutoRemove; - private static String[] whitelistedRoleNames; + public static String[] whitelistedRoleNames; private final char[] validCharacters = {'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '_'}; - private static JDA javaDiscordAPI; + public static JDA javaDiscordAPI; public static int InitializeClient(String clientToken) { @@ -64,19 +70,18 @@ public class DiscordClient extends ListenerAdapter try { - //javaDiscordAPI = new JDABuilder(AccountType.BOT).setToken(clientToken).addEventListeners(new DiscordClient()).build(); - - javaDiscordAPI = JDABuilder - .createDefault(clientToken) - .addEventListeners(new DiscordClient()) - .addEventListeners(new CheckIntents()) + javaDiscordAPI = JDABuilder.createDefault(clientToken) + .setMemberCachePolicy(MemberCachePolicy.ALL) + .setBulkDeleteSplittingEnabled(false) + .disableCache(CacheFlag.VOICE_STATE, CacheFlag.EMOTE) + .setContextEnabled(true) .enableIntents(GatewayIntent.GUILD_MEMBERS) + .addEventListeners(new DiscordClient()) + .addEventListeners(new ShutdownEvents()) .build(); javaDiscordAPI.awaitReady(); - - return 0; } catch (LoginException | InterruptedException e) @@ -84,6 +89,14 @@ public class DiscordClient extends ListenerAdapter e.printStackTrace(); return 1; } + catch (IllegalStateException e) + { + // Don't print exception related to disallowed intents, already handled + if(!e.getMessage().startsWith("Was shutdown trying to await status")) + e.printStackTrace(); + + return 1; + } } public static boolean ShutdownClient() @@ -96,24 +109,24 @@ public class DiscordClient extends ListenerAdapter private static void AssignVars() { // assign vars here instead of every time a message is received, as they do not change - targetTextChannels = new String[DiscordWhitelister.getWhitelisterBotConfig().getList("target-text-channels").size()]; + targetTextChannels = new String[MainConfig.getMainConfig().getList("target-text-channels").size()]; for (int i = 0; i < targetTextChannels.length; ++i) { - targetTextChannels[i] = DiscordWhitelister.getWhitelisterBotConfig().getList("target-text-channels").get(i).toString(); + targetTextChannels[i] = MainConfig.getMainConfig().getList("target-text-channels").get(i).toString(); } - maxWhitelistAmount = DiscordWhitelister.getWhitelisterBotConfig().getInt("max-whitelist-amount"); - limitedWhitelistEnabled = DiscordWhitelister.getWhitelisterBotConfig().getBoolean("limited-whitelist-enabled"); - usernameValidation = DiscordWhitelister.getWhitelisterBotConfig().getBoolean("username-validation"); + maxWhitelistAmount = MainConfig.getMainConfig().getInt("max-whitelist-amount"); + limitedWhitelistEnabled = MainConfig.getMainConfig().getBoolean("limited-whitelist-enabled"); + usernameValidation = MainConfig.getMainConfig().getBoolean("username-validation"); // Set the name of the role to add/remove to/from the user after they have been added/removed to/from the whitelist and if this feature is enabled - whitelistedRoleAutoAdd = DiscordWhitelister.getWhitelisterBotConfig().getBoolean("whitelisted-role-auto-add"); - whitelistedRoleAutoRemove = DiscordWhitelister.getWhitelisterBotConfig().getBoolean("whitelisted-role-auto-remove"); + whitelistedRoleAutoAdd = MainConfig.getMainConfig().getBoolean("whitelisted-role-auto-add"); + whitelistedRoleAutoRemove = MainConfig.getMainConfig().getBoolean("whitelisted-role-auto-remove"); - whitelistedRoleNames = new String[DiscordWhitelister.getWhitelisterBotConfig().getList("whitelisted-roles").size()]; + whitelistedRoleNames = new String[MainConfig.getMainConfig().getList("whitelisted-roles").size()]; for(int i = 0; i < whitelistedRoleNames.length; i++) { - whitelistedRoleNames[i] = DiscordWhitelister.getWhitelisterBotConfig().getList("whitelisted-roles").get(i).toString(); + whitelistedRoleNames[i] = MainConfig.getMainConfig().getList("whitelisted-roles").get(i).toString(); } } @@ -121,7 +134,7 @@ public class DiscordClient extends ListenerAdapter { // build here instead of every time a message is received, as they do not change EmbedBuilder embedBuilderBotInfo = new EmbedBuilder(); - embedBuilderBotInfo.setTitle("Discord Whitelister Bot for Spigot"); + embedBuilderBotInfo.setTitle("Discord Whitelister for Spigot"); embedBuilderBotInfo.addField("Version", VersionInfo.getVersion(), false); embedBuilderBotInfo.addField("Links", ("https://www.spigotmc.org/resources/discord-whitelister.69929/" + System.lineSeparator() + "https://github.com/JoeShimell/DiscordWhitelisterSpigot"), false); embedBuilderBotInfo.addField("Commands", ("**Add:** !whitelist add minecraftUsername" + System.lineSeparator() + "**Remove:** !whitelist remove minecraftUsername"), false); @@ -214,6 +227,28 @@ public class DiscordClient extends ListenerAdapter if (messageContents.toLowerCase().startsWith("!whitelist add") && !DiscordWhitelister.getUseCustomPrefixes() || DiscordWhitelister.getUseCustomPrefixes() && messageContents.toLowerCase().startsWith(whitelistAddPrefix)) { + if(DiscordWhitelister.useOnBanEvents && authorPermissions.isUserIsBanned()) + { + EmbedBuilder bannedMessage = new EmbedBuilder(); + bannedMessage.setColor(new Color(231, 76, 60)); + + if(!DiscordWhitelister.useCustomMessages) + { + bannedMessage.addField("You have been banned!", author.getAsMention() + ", you cannot use this bot as you have been banned!", false); + } + else + { + String customTitle = DiscordWhitelister.getCustomMessagesConfig().getString("banned-title"); + String customMessage = DiscordWhitelister.getCustomMessagesConfig().getString("banned-message"); + customMessage = customMessage.replaceAll("\\{Sender}", author.getAsMention()); // Only checking for {Sender} + + bannedMessage.addField(customTitle, customMessage, false); + } + + channel.sendMessage(bannedMessage.build()).queue(); + return; + } + // Permission check if (!(authorPermissions.isUserCanAddRemove() || authorPermissions.isUserCanAdd() || limitedWhitelistEnabled && authorPermissions.isUserHasLimitedAdd())) { @@ -241,29 +276,17 @@ public class DiscordClient extends ListenerAdapter which records how many times the user has successfully used the whitelist command */ if (limitedWhitelistEnabled && authorPermissions.isUserHasLimitedAdd()) { - if (DiscordWhitelister.getUserList().getString(author.getId()) == null) + if (UserList.getUserList().getString(author.getId()) == null) { - DiscordWhitelister.getUserList().set(author.getId(), new ArrayList()); - try - { - DiscordWhitelister.getUserList().save(DiscordWhitelister.getUserListFile().getPath()); - } - catch (IOException e) - { - EmbedBuilder failure = new EmbedBuilder(); - failure.addField("Internal Error", (author.getAsMention() + ", something went wrong while accessing config files. Please contact a staff member."), false); - failure.setColor(new Color(231, 76, 60)); - channel.sendMessage(failure.build()).queue(); - e.printStackTrace(); - return; - } + UserList.getUserList().set(author.getId(), new ArrayList()); + UserList.SaveStore(); } } boolean usedAllWhitelists = false; try { - usedAllWhitelists = DiscordWhitelister.getRegisteredUsersCount(author.getId()) >= maxWhitelistAmount && + usedAllWhitelists = UserList.getRegisteredUsersCount(author.getId()) >= maxWhitelistAmount && !authorPermissions.isUserCanAddRemove() && !authorPermissions.isUserCanAdd(); } catch (NullPointerException exception) @@ -278,11 +301,17 @@ public class DiscordClient extends ListenerAdapter String messageContentsAfterCommand = ""; if(!DiscordWhitelister.getUseCustomPrefixes()) { - messageContentsAfterCommand = messageContents.substring("!whitelist add".length() + 1); // get everything after !whitelist add[space] + if(messageContents.length() > ("!whitelist add".length() + 1)) + { + messageContentsAfterCommand = messageContents.substring("!whitelist add".length() + 1); // get everything after !whitelist add[space] + } } else { - messageContentsAfterCommand = messageContents.substring(whitelistAddPrefix.length() + 1); // get everything after whitelistAddPrefix[space] + if(messageContents.length() > (whitelistAddPrefix.length() + 1)) + { + messageContentsAfterCommand = messageContents.substring(whitelistAddPrefix.length() + 1); // get everything after whitelistAddPrefix[space] + } } final String finalNameToAdd = messageContentsAfterCommand.replaceAll(" .*", ""); // The name is everything up to the first space @@ -296,7 +325,7 @@ public class DiscordClient extends ListenerAdapter if (onlyHasLimitedAdd) { - timesWhitelisted = DiscordWhitelister.getRegisteredUsersCount(author.getId()); + timesWhitelisted = UserList.getRegisteredUsersCount(author.getId()); // set to current max in case the max whitelist amount was changed if (timesWhitelisted > maxWhitelistAmount) @@ -422,44 +451,22 @@ public class DiscordClient extends ListenerAdapter } } - // EasyWhitelist username store - FileConfiguration tempFileConfiguration = new YamlConfiguration(); - // Default Minecraft username store - File whitelistJSON = (new File(".", "whitelist.json")); - if (onlyHasLimitedAdd) { DiscordWhitelister.getPlugin().getLogger().info(author.getName() + "(" + author.getId() + ") attempted to whitelist: " + finalNameToAdd + ", " + (maxWhitelistAmount - timesWhitelisted) + " whitelists remaining"); } else { DiscordWhitelister.getPlugin().getLogger().info(author.getName() + "(" + author.getId() + ") attempted to whitelist: " + finalNameToAdd); } - if (DiscordWhitelister.useEasyWhitelist) - { - try - { - tempFileConfiguration.load(new File(DiscordWhitelister.easyWhitelist.getDataFolder(), "config.yml")); - } - catch (IOException | InvalidConfigurationException e) - { - EmbedBuilder failure = new EmbedBuilder(); - failure.setColor(new Color(231, 76, 60)); - failure.addField("Internal Error", (author.getAsMention() + ", something went wrong while accessing EasyWhitelist file. Please contact a staff member."), false); - channel.sendMessage(failure.build()).queue(); - e.printStackTrace(); - return; - } - } - boolean alreadyOnWhitelist = false; - if(DiscordWhitelister.useEasyWhitelist) + if(WhitelistedPlayers.usingEasyWhitelist) { - if (tempFileConfiguration.getStringList("whitelisted").contains(finalNameToAdd)) + if (WhitelistedPlayers.CheckForPlayerEasyWhitelist(finalNameToAdd)) { alreadyOnWhitelist = true; } } - else if (checkWhitelistJSON(whitelistJSON, finalNameToAdd)) + else if (WhitelistedPlayers.CheckForPlayer(finalNameToAdd)) { alreadyOnWhitelist = true; } @@ -487,7 +494,7 @@ public class DiscordClient extends ListenerAdapter return; } - if (DiscordWhitelister.getRemovedList().get(finalNameToAdd) != null) // If the user has been removed before + if (RemovedList.CheckStoreForPlayer(finalNameToAdd)) // If the user has been removed before { if (onlyHasLimitedAdd) { @@ -496,17 +503,17 @@ public class DiscordClient extends ListenerAdapter if(!DiscordWhitelister.useCustomMessages) { - embedBuilderRemovedByStaff.addField("This user was previously removed by a staff member", (author.getAsMention() + ", this user was previously removed by a staff member (<@" + DiscordWhitelister.getRemovedList().get(finalNameToAdd) + ">)." + embedBuilderRemovedByStaff.addField("This user was previously removed by a staff member", (author.getAsMention() + ", this user was previously removed by a staff member (<@" + RemovedList.getRemovedPlayers().get(finalNameToAdd) + ">)." + System.lineSeparator() + "Please ask a user with higher permissions to add this user." + System.lineSeparator()), false); embedBuilderRemovedByStaff.addField("Whitelists Remaining", ("You have **" + (maxWhitelistAmount - timesWhitelisted) - + " out of " + DiscordWhitelister.getWhitelisterBotConfig().getString("max-whitelist-amount") + "** whitelists remaining."), false); + + " out of " + MainConfig.getMainConfig().getString("max-whitelist-amount") + "** whitelists remaining."), false); } else { String customTitle = DiscordWhitelister.getCustomMessagesConfig().getString("user-was-removed-title"); String customMessage = DiscordWhitelister.getCustomMessagesConfig().getString("user-was-removed"); String customWhitelistsRemaining = DiscordWhitelister.getCustomMessagesConfig().getString("whitelists-remaining"); - String staffMemberMention = "<@" + DiscordWhitelister.getRemovedList().get(finalNameToAdd) + ">"; + String staffMemberMention = "<@" + RemovedList.getRemovedPlayers().get(finalNameToAdd) + ">"; customMessage = customMessage.replaceAll("\\{Sender}", author.getAsMention()); customMessage = customMessage.replaceAll("\\{StaffMember}", staffMemberMention); @@ -522,21 +529,60 @@ public class DiscordClient extends ListenerAdapter } else // Remove from removed list { - DiscordWhitelister.getRemovedList().set(finalNameToAdd, null); - - try - { - DiscordWhitelister.getRemovedList().save(DiscordWhitelister.getRemovedListFile().getPath()); - } catch (IOException e) - { - e.printStackTrace(); - } + RemovedList.getRemovedPlayers().set(finalNameToAdd, null); + RemovedList.SaveStore(); DiscordWhitelister.getPlugin().getLogger().info(finalNameToAdd + " has been removed from the removed list by " + author.getName() + "(" + author.getId() + ")"); } } + // In-game list check + if(DiscordWhitelister.useInGameAddRemoves) + { + if(InGameRemovedList.CheckStoreForPlayer(finalNameToAdd)) + { + if(onlyHasLimitedAdd) + { + EmbedBuilder embedBuilderRemovedByStaff = new EmbedBuilder(); + embedBuilderRemovedByStaff.setColor(new Color(231, 76, 60)); + + if(!DiscordWhitelister.useCustomMessages) + { + embedBuilderRemovedByStaff.addField("This user was previously removed by a staff member", (author.getAsMention() + ", this user was previously removed by a staff member in-game (" + InGameRemovedList.getRemovedPlayers().get(finalNameToAdd) + ")." + + System.lineSeparator() + "Please ask a user with higher permissions to add this user." + System.lineSeparator()), false); + embedBuilderRemovedByStaff.addField("Whitelists Remaining", ("You have **" + (maxWhitelistAmount - timesWhitelisted) + + " out of " + MainConfig.getMainConfig().getString("max-whitelist-amount") + "** whitelists remaining."), false); + } + else + { + String customTitle = DiscordWhitelister.getCustomMessagesConfig().getString("user-was-removed-in-game-title"); + String customMessage = DiscordWhitelister.getCustomMessagesConfig().getString("user-was-removed-in-game"); + String customWhitelistsRemaining = DiscordWhitelister.getCustomMessagesConfig().getString("whitelists-remaining"); + String inGameStaffMember = InGameRemovedList.getRemovedPlayers().getString(finalNameToAdd); + + customMessage = customMessage.replaceAll("\\{Sender}", author.getAsMention()); + customMessage = customMessage.replaceAll("\\{StaffMember}", inGameStaffMember); + + customWhitelistsRemaining = customWhitelistsRemaining.replaceAll("\\{RemainingWhitelists}", String.valueOf((maxWhitelistAmount - timesWhitelisted))); + customWhitelistsRemaining = customWhitelistsRemaining.replaceAll("\\{MaxWhitelistAmount}", String.valueOf(maxWhitelistAmount)); + + embedBuilderRemovedByStaff.addField(customTitle, customMessage + " " + customWhitelistsRemaining, false); + } + + channel.sendMessage(embedBuilderRemovedByStaff.build()).queue(); + return; + } + else // Remove from in-game removed list + { + InGameRemovedList.RemoveUserFromStore(finalNameToAdd); + + DiscordWhitelister.getPlugin().getLogger().info(finalNameToAdd + " has been removed from in-game-removed-list.yml by " + author.getName() + + "(" + author.getId() + ")"); + } + } + } + /* Do as much as possible off the main server thread. convert username into UUID to avoid depreciation and rate limits (according to https://minotar.net/) */ String playerUUID = minecraftUsernameToUUID(finalNameToAdd); @@ -621,42 +667,59 @@ public class DiscordClient extends ListenerAdapter int tempTimesWhitelisted = timesWhitelisted; - if (onlyHasLimitedAdd) { - if (tempTimesWhitelisted < maxWhitelistAmount) { + if (onlyHasLimitedAdd) + { + if (tempTimesWhitelisted < maxWhitelistAmount) + { tempTimesWhitelisted = timesWhitelisted + 1; } } final int finalTimesWhitelisted = tempTimesWhitelisted; - final int successfulTimesWhitelisted = maxWhitelistAmount - finalTimesWhitelisted; - final int failedTimesWhitelisted = maxWhitelistAmount - timesWhitelisted; +// final int successfulTimesWhitelisted = maxWhitelistAmount - finalTimesWhitelisted; +// final int failedTimesWhitelisted = maxWhitelistAmount - timesWhitelisted; - if (!DiscordWhitelister.useEasyWhitelist) { - if (authorPermissions.isUserCanUseCommand()) { - executeServerCommand("whitelist add " + finalNameToAdd); - } + AtomicBoolean successfulWhitelist = new AtomicBoolean(false); + + if (!WhitelistedPlayers.usingEasyWhitelist) + { + if (authorPermissions.isUserCanUseCommand()) + ExecuteServerCommand("whitelist add " + finalNameToAdd); } - if (DiscordWhitelister.useEasyWhitelist) { + if (WhitelistedPlayers.usingEasyWhitelist) + { if (!invalidMinecraftName) // have to do this else the easy whitelist plugin will add the name regardless of whether it is valid on not { - if (authorPermissions.isUserCanUseCommand()) { - executeServerCommand("easywl add " + finalNameToAdd); - } + if (authorPermissions.isUserCanUseCommand()) + ExecuteServerCommand("easywl add " + finalNameToAdd); } // run through the server so that the check doesn't execute before the server has had a chance to run the whitelist command -- unsure if this is the best way of doing this, but it works DiscordWhitelister.getPlugin().getServer().getScheduler().callSyncMethod(DiscordWhitelister.getPlugin(), () -> { - try { - tempFileConfiguration.load(new File(DiscordWhitelister.easyWhitelist.getDataFolder(), "config.yml")); - } catch (IOException | InvalidConfigurationException e) { - e.printStackTrace(); - } - - if (!invalidMinecraftName && tempFileConfiguration.getStringList("whitelisted").contains(finalNameToAdd)) { + if (!invalidMinecraftName && WhitelistedPlayers.CheckForPlayerEasyWhitelist(finalNameToAdd)) + { channel.sendMessage(embedBuilderWhitelistSuccess.build()).queue(); + // For instructional message + successfulWhitelist.set(true); + + // If the user is whitelisted assign perms if enabled + if(DiscordWhitelister.useUltraPerms) + { + AssignPermsToUser(finalNameToAdd, PermissionsConfig.getPermissionsConfig().getStringList("perms-on-whitelist")); + } + + if(DiscordWhitelister.useOnWhitelistCommands) + { + List commandsToExecute = OnWhitelistCommandsConfig.getPermissionsConfig().getStringList("on-whitelist-commands"); + for(int i = 0; i < commandsToExecute.size(); i++) + { + CheckAndExecuteCommand(commandsToExecute.get(i), finalNameToAdd); + } + } + // Add role to user when they have been added to the whitelist if need be if(whitelistedRoleAutoAdd) { @@ -698,124 +761,247 @@ public class DiscordClient extends ListenerAdapter } } - if (onlyHasLimitedAdd) { - - DiscordWhitelister.addRegisteredUser(author.getId(), finalNameToAdd); - DiscordWhitelister.getPlugin().getLogger().info(author.getName() + "(" + author.getId() + ") successfully added " + finalNameToAdd - + " to the whitelist, " + successfulTimesWhitelisted + " whitelists remaining."); - } - } else { - channel.sendMessage(embedBuilderWhitelistFailure.build()).queue(); - } - return null; - }); - } else { - DiscordWhitelister.getPlugin().getServer().getScheduler().callSyncMethod(DiscordWhitelister.getPlugin(), () -> - { - if (checkWhitelistJSON(whitelistJSON, finalNameToAdd)) { - channel.sendMessage(embedBuilderWhitelistSuccess.build()).queue(); - - // Add role to user when they have been added to the whitelist if need be - if(whitelistedRoleAutoAdd) + // Instructional message -- TODO: DON'T HAVE 2 INSTANCES OF THIS + if(successfulWhitelist.get()) { - List whitelistRoles = new LinkedList<>(); - try + if(MainConfig.getMainConfig().getBoolean("send-instructional-message-on-whitelist")) { - if(!DiscordWhitelister.useIdForRoles) + EmbedBuilder embedBuilderInstructionalMessage = new EmbedBuilder(); + embedBuilderInstructionalMessage.setColor(new Color(104, 109, 224)); + + if(!DiscordWhitelister.useCustomMessages) { - for (int i = 0; i < whitelistedRoleNames.length; i++) - { - // Use channel, get guild instead of JDA so that it is server specific - List rolesFoundWithName = channel.getGuild().getRolesByName(whitelistedRoleNames[i], false); - whitelistRoles.addAll(rolesFoundWithName); - } + String addCommandExample = "!whitelist add"; + if(DiscordWhitelister.useCustomPrefixes) + addCommandExample = CustomPrefixConfig.getCustomPrefixesConfig().getString("whitelist-add-prefix").trim(); + + embedBuilderInstructionalMessage.addField("How to Whitelist", ("Use `" + addCommandExample + " ` to whitelist yourself.\n" + + "In the case of whitelisting an incorrect name, please contact a staff member to clear it from the whitelist."), false); } else { - for (int i = 0; i < whitelistedRoleNames.length; i++) + String customTitle = CustomMessagesConfig.getCustomMessagesConfig().getString("instructional-message-title"); + String customMessage = CustomMessagesConfig.getCustomMessagesConfig().getString("instructional-message"); + + embedBuilderInstructionalMessage.addField(customTitle, customMessage, false); + } + + if(!MainConfig.getMainConfig().getBoolean("use-timer-for-instructional-message")) + { + channel.sendMessage(embedBuilderInstructionalMessage.build()).queue(); + } + else + { + int waitTime = MainConfig.getMainConfig().getInt("timer-wait-time-in-seconds"); + + try { - if(channel.getGuild().getRoleById(whitelistedRoleNames[i]) != null) - whitelistRoles.add(channel.getGuild().getRoleById(whitelistedRoleNames[i])); + TimeUnit.SECONDS.sleep(waitTime); + channel.sendMessage(embedBuilderInstructionalMessage.build()).queue(); + } + catch (InterruptedException e) + { + e.printStackTrace(); } } - - Member member = messageReceivedEvent.getMember(); - - if(whitelistRoles != null) - { - whitelistRoles.forEach(role -> - { - messageReceivedEvent.getGuild().addRoleToMember(member, role).queue(); - }); - } - } - catch (Exception e) - { - DiscordWhitelister.getPlugin().getLogger().severe("Could not add role with name/id to " + author.getName() + ", check the config and that the bot has the Manage Roles permission"); - e.printStackTrace(); } } - if (onlyHasLimitedAdd) { - - DiscordWhitelister.addRegisteredUser(author.getId(), finalNameToAdd); + if (onlyHasLimitedAdd) + { + UserList.addRegisteredUser(author.getId(), finalNameToAdd); DiscordWhitelister.getPlugin().getLogger().info(author.getName() + "(" + author.getId() + ") successfully added " + finalNameToAdd - + " to the whitelist, " + failedTimesWhitelisted + " whitelists remaining."); + + " to the whitelist, " + (maxWhitelistAmount - finalTimesWhitelisted) + " whitelists remaining."); } - } else { + } + else + { channel.sendMessage(embedBuilderWhitelistFailure.build()).queue(); } return null; }); } + else + { + DiscordWhitelister.getPlugin().getServer().getScheduler().callSyncMethod(DiscordWhitelister.getPlugin(), () -> + { + if (WhitelistedPlayers.CheckForPlayer(finalNameToAdd)) + { + channel.sendMessage(embedBuilderWhitelistSuccess.build()).queue(); + // For instructional message + successfulWhitelist.set(true); + + // If the user is whitelisted assign perms if enabled + if(DiscordWhitelister.useUltraPerms) + { + AssignPermsToUser(finalNameToAdd, PermissionsConfig.getPermissionsConfig().getStringList("perms-on-whitelist")); + } + + + if(DiscordWhitelister.useOnWhitelistCommands) + { + List commandsToExecute = OnWhitelistCommandsConfig.getPermissionsConfig().getStringList("on-whitelist-commands"); + for(int i = 0; i < commandsToExecute.size(); i++) + { + CheckAndExecuteCommand(commandsToExecute.get(i), finalNameToAdd); + } + } + + // Add role to user when they have been added to the whitelist if need be + if(whitelistedRoleAutoAdd) + { + List whitelistRoles = new LinkedList<>(); + try + { + if(!DiscordWhitelister.useIdForRoles) + { + for (int i = 0; i < whitelistedRoleNames.length; i++) + { + // Use channel, get guild instead of JDA so that it is server specific + List rolesFoundWithName = channel.getGuild().getRolesByName(whitelistedRoleNames[i], false); + whitelistRoles.addAll(rolesFoundWithName); + } + } + else + { + for (int i = 0; i < whitelistedRoleNames.length; i++) + { + if(channel.getGuild().getRoleById(whitelistedRoleNames[i]) != null) + whitelistRoles.add(channel.getGuild().getRoleById(whitelistedRoleNames[i])); + } + } + + Member member = messageReceivedEvent.getMember(); + + if(whitelistRoles != null) + { + whitelistRoles.forEach(role -> + { + messageReceivedEvent.getGuild().addRoleToMember(member, role).queue(); + }); + } + } + catch (Exception e) + { + DiscordWhitelister.getPlugin().getLogger().severe("Could not add role with name/id to " + author.getName() + ", check the config and that the bot has the Manage Roles permission"); + e.printStackTrace(); + } + + // Instructional message + if(successfulWhitelist.get()) + { + if(MainConfig.getMainConfig().getBoolean("send-instructional-message-on-whitelist")) + { + EmbedBuilder embedBuilderInstructionalMessage = new EmbedBuilder(); + embedBuilderInstructionalMessage.setColor(new Color(104, 109, 224)); + + if(!DiscordWhitelister.useCustomMessages) + { + String addCommandExample = "!whitelist add"; + if(DiscordWhitelister.useCustomPrefixes) + addCommandExample = CustomPrefixConfig.getCustomPrefixesConfig().getString("whitelist-add-prefix").trim(); + + embedBuilderInstructionalMessage.addField("How to Whitelist", ("Use `" + addCommandExample + " ` to whitelist yourself.\n" + + "In the case of whitelisting an incorrect name, please contact a staff member to clear it from the whitelist."), false); + } + else + { + String customTitle = CustomMessagesConfig.getCustomMessagesConfig().getString("instructional-message-title"); + String customMessage = CustomMessagesConfig.getCustomMessagesConfig().getString("instructional-message"); + + embedBuilderInstructionalMessage.addField(customTitle, customMessage, false); + } + + if(!MainConfig.getMainConfig().getBoolean("use-timer-for-instructional-message")) + { + channel.sendMessage(embedBuilderInstructionalMessage.build()).queue(); + } + else + { + int waitTime = MainConfig.getMainConfig().getInt("timer-wait-time-in-seconds"); + + // Run on a new thread to not block main thread + Thread whitelisterTimerThread = new Thread(() -> + { + try + { + TimeUnit.SECONDS.sleep(waitTime); + channel.sendMessage(embedBuilderInstructionalMessage.build()).queue(); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + }); + + whitelisterTimerThread.start(); + } + } + } + } + + if (onlyHasLimitedAdd) + { + + UserList.addRegisteredUser(author.getId(), finalNameToAdd); + + DiscordWhitelister.getPlugin().getLogger().info(author.getName() + "(" + author.getId() + ") successfully added " + finalNameToAdd + + " to the whitelist, " + (maxWhitelistAmount - finalTimesWhitelisted) + " whitelists remaining."); + } + } + else + { + channel.sendMessage(embedBuilderWhitelistFailure.build()).queue(); + } + return null; + }); + } } } } + // Remove Command if (messageContents.toLowerCase().startsWith("!whitelist remove") && !DiscordWhitelister.getUseCustomPrefixes() || DiscordWhitelister.getUseCustomPrefixes() && messageContents.toLowerCase().startsWith(whitelistRemovePrefix)) { - if (authorPermissions.isUserCanAddRemove()) { + if (authorPermissions.isUserCanAddRemove()) + { messageContents = messageContents.toLowerCase(); String messageContentsAfterCommand = ""; if(!DiscordWhitelister.useCustomPrefixes) { - messageContentsAfterCommand = messageContents.substring("!whitelist remove".length() + 1); // get everything after !whitelist remove[space] + if(messageContents.length() > ("!whitelist remove".length() + 1)) + { + messageContentsAfterCommand = messageContents.substring("!whitelist remove".length() + 1); // get everything after !whitelist remove[space] + } } else { - messageContentsAfterCommand = messageContents.substring(whitelistRemovePrefix.length() + 1); // get everything after whitelistRemovePrefix[space] + if(messageContents.length() > (whitelistRemovePrefix.length() + 1)) + { + messageContentsAfterCommand = messageContents.substring(whitelistRemovePrefix.length() + 1); // get everything after whitelistRemovePrefix[space] + } } final String finalNameToRemove = messageContentsAfterCommand.replaceAll(" .*", ""); // The name is everything up to the first space - if (finalNameToRemove.isEmpty()) { + if (finalNameToRemove.isEmpty()) + { channel.sendMessage(removeCommandInfo).queue(); return; - } else { - // easy whitelist - FileConfiguration tempFileConfiguration = new YamlConfiguration(); - // default whitelist - File whitelistJSON = (new File(".", "whitelist.json")); - + } + else + { DiscordWhitelister.getPlugin().getLogger().info(author.getName() + "(" + author.getId() + ") attempted to remove " + finalNameToRemove + " from the whitelist"); - if (DiscordWhitelister.useEasyWhitelist) { - try { - tempFileConfiguration.load(new File(DiscordWhitelister.easyWhitelist.getDataFolder(), "config.yml")); - } catch (IOException | InvalidConfigurationException e) { - e.printStackTrace(); - } - } - boolean notOnWhitelist = false; - if (DiscordWhitelister.useEasyWhitelist) + if (WhitelistedPlayers.usingEasyWhitelist) { - if (!tempFileConfiguration.getStringList("whitelisted").contains(finalNameToRemove)) + if (!WhitelistedPlayers.CheckForPlayerEasyWhitelist(finalNameToRemove)) { notOnWhitelist = true; @@ -840,7 +1026,7 @@ public class DiscordClient extends ListenerAdapter } } - if (!DiscordWhitelister.useEasyWhitelist && !checkWhitelistJSON(whitelistJSON, finalNameToRemove)) + if (!WhitelistedPlayers.usingEasyWhitelist && !WhitelistedPlayers.CheckForPlayer(finalNameToRemove)) { notOnWhitelist = true; @@ -864,25 +1050,13 @@ public class DiscordClient extends ListenerAdapter channel.sendMessage(embedBuilderInfo.build()).queue(); } + // not not on whitelist, nice if (!notOnWhitelist) { - if (DiscordWhitelister.useEasyWhitelist) - { - try - { - tempFileConfiguration.load(new File(DiscordWhitelister.easyWhitelist.getDataFolder(), "config.yml")); - } - catch (IOException | InvalidConfigurationException e) - { - e.printStackTrace(); - } - - executeServerCommand("easywl remove " + finalNameToRemove); - } + if (WhitelistedPlayers.usingEasyWhitelist) + ExecuteServerCommand("easywl remove " + finalNameToRemove); else - { - executeServerCommand("whitelist remove " + finalNameToRemove); - } + ExecuteServerCommand("whitelist remove " + finalNameToRemove); // Configure message here instead of on the main thread - this means this will run even if the message is never sent, but is a good trade off (I think) EmbedBuilder embedBuilderSuccess = new EmbedBuilder(); @@ -912,18 +1086,22 @@ public class DiscordClient extends ListenerAdapter "This should never happen, you may have to remove the player manually and report the issue."), false); - if (DiscordWhitelister.useEasyWhitelist) { + if (WhitelistedPlayers.usingEasyWhitelist) + { DiscordWhitelister.getPlugin().getServer().getScheduler().callSyncMethod(DiscordWhitelister.getPlugin(), () -> { - try { - tempFileConfiguration.load(new File(DiscordWhitelister.easyWhitelist.getDataFolder(), "config.yml")); - } catch (IOException | InvalidConfigurationException e) { - e.printStackTrace(); - } - - if (!tempFileConfiguration.getStringList("whitelisted").contains(finalNameToRemove)) { + if (!WhitelistedPlayers.CheckForPlayerEasyWhitelist(finalNameToRemove)) + { channel.sendMessage(embedBuilderSuccess.build()).queue(); + // Remove Perms if enabled + if(DiscordWhitelister.useUltraPerms) + { + RemovePermsFromUser(finalNameToRemove, PermissionsConfig.getPermissionsConfig().getStringList("perms-on-whitelist")); + } + + ClearPlayerFromUserList(finalNameToRemove); + // Remove role from user when they have been removed from the whitelist if need be if(whitelistedRoleAutoRemove) { @@ -966,22 +1144,34 @@ public class DiscordClient extends ListenerAdapter } // if the name is not on the list - if (DiscordWhitelister.getRemovedList().get(finalNameToRemove) == null) + if (RemovedList.getRemovedPlayers().get(finalNameToRemove) == null) { - DiscordWhitelister.getRemovedList().set(finalNameToRemove, author.getId()); - DiscordWhitelister.getRemovedList().save(DiscordWhitelister.getRemovedListFile().getPath()); + RemovedList.getRemovedPlayers().set(finalNameToRemove, author.getId()); + RemovedList.SaveStore(); } - } else { + } + else + { channel.sendMessage(embedBuilderFailure.build()).queue(); } return null; }); - } else { + } + else + { DiscordWhitelister.getPlugin().getServer().getScheduler().callSyncMethod(DiscordWhitelister.getPlugin(), () -> { - if (!checkWhitelistJSON(whitelistJSON, finalNameToRemove)) { + if (!WhitelistedPlayers.CheckForPlayer(finalNameToRemove)) { channel.sendMessage(embedBuilderSuccess.build()).queue(); + // Remove Perms if enabled + if(DiscordWhitelister.useUltraPerms) + { + RemovePermsFromUser(finalNameToRemove, PermissionsConfig.getPermissionsConfig().getStringList("perms-on-whitelist")); + } + + ClearPlayerFromUserList(finalNameToRemove); + // Remove role from user when they have been removed from the whitelist if need be if(whitelistedRoleAutoRemove) { @@ -1022,11 +1212,14 @@ public class DiscordClient extends ListenerAdapter } // if the name is not on the list - if (DiscordWhitelister.getRemovedList().get(finalNameToRemove) == null) { - DiscordWhitelister.getRemovedList().set(finalNameToRemove, author.getId()); - DiscordWhitelister.getRemovedList().save(DiscordWhitelister.getRemovedListFile().getPath()); + if (!RemovedList.CheckStoreForPlayer(finalNameToRemove)) + { + RemovedList.getRemovedPlayers().set(finalNameToRemove, author.getId()); + RemovedList.SaveStore(); } - } else { + } + else + { channel.sendMessage(embedBuilderFailure.build()).queue(); } return null; @@ -1040,7 +1233,7 @@ public class DiscordClient extends ListenerAdapter if (authorPermissions.isUserCanAdd() && !authorPermissions.isUserCanAddRemove()) { - String higherPermRoles = DiscordWhitelister.getWhitelisterBotConfig().getList("add-remove-roles").toString(); + String higherPermRoles = MainConfig.getMainConfig().getList("add-remove-roles").toString(); higherPermRoles = higherPermRoles.replaceAll("\\[", ""); higherPermRoles = higherPermRoles.replaceAll("]", ""); @@ -1085,61 +1278,510 @@ public class DiscordClient extends ListenerAdapter channel.sendMessage(embedBuilderFailure.build()).queue(); } + + // Clear Whitelists command + if(messageContents.toLowerCase().startsWith("!clearname") && !DiscordWhitelister.getUseCustomPrefixes() + || DiscordWhitelister.getUseCustomPrefixes() && messageContents.toLowerCase().startsWith(clearNamePrefix)) + { + // !clearname + // TODO: !clearnames <@DiscordID> + + // Check permissions + if(authorPermissions.isUserCanUseClear()) + { + // Check if empty command + if(messageContents.toLowerCase().trim().equals("!clearname") && !DiscordWhitelister.getUseCustomPrefixes() + || messageContents.toLowerCase().trim().equals(clearNamePrefix) && DiscordWhitelister.getUseCustomPrefixes()) + { + // Send info message + EmbedBuilder embedBuilderClearInfo = new EmbedBuilder(); + embedBuilderClearInfo.setColor(new Color(104, 109, 224)); + + if(!DiscordWhitelister.getUseCustomPrefixes()) + embedBuilderClearInfo.addField("Clear Name Command", "Usage: `!clearname `\n", false); + else + embedBuilderClearInfo.addField("Clear Name Command", "Usage: `" + clearNamePrefix + " `\n", false); + + + channel.sendMessage(embedBuilderClearInfo.build()).queue(); + + return; + } + + // If command is not empty check for args + String[] splitMessage = messageContents.toLowerCase().trim().split(" "); + + int userNameIndex = 1; + + if(DiscordWhitelister.getUseCustomPrefixes()) + { + String[] customPrefixCount = clearNamePrefix.trim().split(" "); + userNameIndex = customPrefixCount.length; // Don't + 1 as index starts at 0, length doesn't + } + + // Search for target name & linked ID + Boolean nameFound = false; + String targetDiscordId = ""; + List targetWhitelistedPlayers = Collections.emptyList(); + int nameToClearIndex = 0; + + Yaml userYaml = new Yaml(); + + try + { + InputStream inputStream = new FileInputStream(UserList.getUserListFile()); + + // Check if input stream is empty + PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream); + int b = pushbackInputStream.read(); + + // Make sure the user list is not empty + if(b != -1) + { + pushbackInputStream.unread(b); + Map> userListObject = userYaml.load(pushbackInputStream); + + // Search for name and Id linked to it + for(Map.Entry> entry : userListObject.entrySet()) + { + for(int i = 0; i < entry.getValue().size(); i++) + { + if(entry.getValue().get(i).equals(splitMessage[userNameIndex])) // Target name + { + // Found the target name + targetDiscordId = entry.getKey(); + targetWhitelistedPlayers = entry.getValue(); + nameToClearIndex = i; + nameFound = true; + } + } + } + } + } + catch (IOException e) + { + e.printStackTrace(); + } + + if(nameFound) + { + List updatedTargetWhitelistedPlayers = targetWhitelistedPlayers; + + // Check count - clear id entirely if only 1 entry + if(updatedTargetWhitelistedPlayers.size() > 1) + { + updatedTargetWhitelistedPlayers.remove(nameToClearIndex); // Clear name + + // Set the updated list in the config + UserList.getUserList().set(targetDiscordId, updatedTargetWhitelistedPlayers); + } + else // Remove entirely + { + UserList.getUserList().set(targetDiscordId, null); + } + + UserList.SaveStore(); + + // Un-whitelist and remove perms if enabled + if(MainConfig.getMainConfig().getBoolean("unwhitelist-and-clear-perms-on-name-clear")) + { + // Remove name from the whitelist + if(!WhitelistedPlayers.usingEasyWhitelist) + { + DiscordClient.ExecuteServerCommand("whitelist remove " + splitMessage[userNameIndex]); + } + else + { + DiscordClient.ExecuteServerCommand("easywl remove " + splitMessage[userNameIndex]); + } + + // Clear permissions + if(DiscordWhitelister.useUltraPerms) + DiscordClient.RemovePermsFromUser(splitMessage[userNameIndex], PermissionsConfig.getPermissionsConfig().getStringList("perms-on-whitelist")); + } + + // Success message + EmbedBuilder embedBuilderClearSuccess = new EmbedBuilder(); + embedBuilderClearSuccess.setColor(new Color(46, 204, 113)); + + if(DiscordWhitelister.useCustomMessages) + { + String clearNameTitle = CustomMessagesConfig.getCustomMessagesConfig().getString("clear-name-success-title"); + String clearNameMessage = CustomMessagesConfig.getCustomMessagesConfig().getString("clear-name-success-message"); + + clearNameMessage = clearNameMessage.replaceAll("\\{Sender}", author.getAsMention()); + clearNameMessage = clearNameMessage.replaceAll("\\{MinecraftUsername}", splitMessage[userNameIndex]); + clearNameMessage = clearNameMessage.replaceAll("\\{DiscordID}", "<@" + targetDiscordId + ">"); + + clearNameTitle = clearNameTitle.replaceAll("\\{MinecraftUsername}", splitMessage[userNameIndex]); + + embedBuilderClearSuccess.addField(clearNameTitle, clearNameMessage,false); + } + else + { + embedBuilderClearSuccess.addField("Successfully Cleared Name", author.getAsMention() + + " successfully cleared username `" + splitMessage[userNameIndex] + + "` from <@" + targetDiscordId + ">'s whitelisted users.", false); + } + + channel.sendMessage(embedBuilderClearSuccess.build()).queue(); + } + else + { + EmbedBuilder embedBuilderNameNotFound = new EmbedBuilder(); + embedBuilderNameNotFound.setColor(new Color(231, 76, 60)); + + if(!DiscordWhitelister.useCustomMessages) + { + embedBuilderNameNotFound.addField(splitMessage[userNameIndex] +" not Found", (author.getAsMention() + ", could not find name " + splitMessage[userNameIndex] + " to clear in user list."), false); + } + else + { + String customTitle = CustomMessagesConfig.getCustomMessagesConfig().getString("clear-name-failure-title"); + String customMessage = CustomMessagesConfig.getCustomMessagesConfig().getString("clear-name-failure-message"); + customMessage = customMessage.replaceAll("\\{Sender}", author.getAsMention()); + customMessage = customMessage.replaceAll("\\{MinecraftUsername}", splitMessage[userNameIndex]); + customTitle = customTitle.replaceAll("\\{MinecraftUsername}", splitMessage[userNameIndex]); + + embedBuilderNameNotFound.addField(customTitle, customMessage, false); + } + + channel.sendMessage(embedBuilderNameNotFound.build()).queue(); + } + } + else // Don't have permission + { + EmbedBuilder insufficientPermission = new EmbedBuilder(); + insufficientPermission.setColor(new Color(231, 76, 60)); + + if(!DiscordWhitelister.useCustomMessages) + { + insufficientPermission.addField("Insufficient Permissions", (author.getAsMention() + ", you do not have permission to use this command."), false); + } + else + { + String customTitle = DiscordWhitelister.getCustomMessagesConfig().getString("insufficient-permissions-title"); + String customMessage = DiscordWhitelister.getCustomMessagesConfig().getString("insufficient-permissions"); + customMessage = customMessage.replaceAll("\\{Sender}", author.getAsMention()); // Only checking for {Sender} + + insufficientPermission.addField(customTitle, customMessage, false); + } + + channel.sendMessage(insufficientPermission.build()).queue(); + return; + } + } + + if(messageContents.toLowerCase().startsWith("!clearban") && !DiscordWhitelister.getUseCustomPrefixes() + || DiscordWhitelister.getUseCustomPrefixes() && messageContents.toLowerCase().startsWith(clearBanPrefix)) + { + if(authorPermissions.isUserCanUseClear()) + { + + + // Check if empty command + if(messageContents.toLowerCase().trim().equals("!clearban") && !DiscordWhitelister.getUseCustomPrefixes() + || messageContents.toLowerCase().trim().equals(clearBanPrefix) && DiscordWhitelister.getUseCustomPrefixes()) + { + // Send info message + EmbedBuilder embedBuilderClearInfo = new EmbedBuilder(); + embedBuilderClearInfo.setColor(new Color(104, 109, 224)); + + if(!DiscordWhitelister.getUseCustomPrefixes()) + embedBuilderClearInfo.addField("Clear Ban Command", "Usage: `!clearban `\n", false); + else + embedBuilderClearInfo.addField("Clear Ban Command", "Usage: `" + clearBanPrefix + " `\n", false); + + channel.sendMessage(embedBuilderClearInfo.build()).queue(); + + return; + } + + // If command is not empty check for args + String[] splitMessage = messageContents.toLowerCase().trim().split(" "); + + int userNameIndex = 1; + + if(DiscordWhitelister.getUseCustomPrefixes()) + { + String[] customPrefixCount = clearBanPrefix.trim().split(" "); + userNameIndex = customPrefixCount.length; // Don't + 1 as index starts at 0, length doesn't + } + + String targetName = splitMessage[userNameIndex]; + + // Check both removed lists for target name + boolean nameFoundInLists = false; + + // Remove name from removed list if found + if(RemovedList.CheckStoreForPlayer(targetName)) + { + RemovedList.getRemovedPlayers().set(targetName, null); + RemovedList.SaveStore(); + + nameFoundInLists = true; + } + + if(InGameRemovedList.CheckStoreForPlayer(targetName)) + { + InGameRemovedList.RemoveUserFromStore(targetName); + + nameFoundInLists = true; + } + + if(nameFoundInLists) + { + EmbedBuilder clearBanSuccessEmbed = new EmbedBuilder(); + clearBanSuccessEmbed.setColor(new Color(46, 204, 113)); + + if(!DiscordWhitelister.useCustomMessages) + { + clearBanSuccessEmbed.addField("Successfully Cleared `" + targetName + "`", + author.getAsMention() + " has successfully cleared `" + targetName + "` from the removed list(s).", false); + } + else + { + String customTitle = CustomMessagesConfig.getCustomMessagesConfig().getString("clear-ban-success-title"); + String customMessage = CustomMessagesConfig.getCustomMessagesConfig().getString("clear-ban-success-message"); + customMessage = customMessage.replaceAll("\\{Sender}", author.getAsMention()); + customMessage = customMessage.replaceAll("\\{MinecraftUsername}", targetName); + customTitle = customTitle.replaceAll("\\{MinecraftUsername}", targetName); + + clearBanSuccessEmbed.addField(customTitle, customMessage, false); + } + + channel.sendMessage(clearBanSuccessEmbed.build()).queue(); + return; + } + else + { + EmbedBuilder clearBanFailureEmbed = new EmbedBuilder(); + clearBanFailureEmbed.setColor(new Color(231, 76, 60)); + + if(!DiscordWhitelister.useCustomMessages) + { + clearBanFailureEmbed.addField("Failed to Clear `" + targetName + "`", + author.getAsMention() + ", `" + targetName + "` cannot be found in any of the removed lists!", false); + } + else + { + String customTitle = CustomMessagesConfig.getCustomMessagesConfig().getString("clear-ban-failure-title"); + String customMessage = CustomMessagesConfig.getCustomMessagesConfig().getString("clear-ban-failure-message"); + customMessage = customMessage.replaceAll("\\{Sender}", author.getAsMention()); + customMessage = customMessage.replaceAll("\\{MinecraftUsername}", targetName); + customTitle = customTitle.replaceAll("\\{MinecraftUsername}", targetName); + + clearBanFailureEmbed.addField(customTitle, customMessage, false); + } + + channel.sendMessage(clearBanFailureEmbed.build()).queue(); + return; + } + } + else + { + EmbedBuilder insufficientPermission = new EmbedBuilder(); + insufficientPermission.setColor(new Color(231, 76, 60)); + + if(!DiscordWhitelister.useCustomMessages) + { + insufficientPermission.addField("Insufficient Permissions", (author.getAsMention() + ", you do not have permission to use this command."), false); + } + else + { + String customTitle = DiscordWhitelister.getCustomMessagesConfig().getString("insufficient-permissions-title"); + String customMessage = DiscordWhitelister.getCustomMessagesConfig().getString("insufficient-permissions"); + customMessage = customMessage.replaceAll("\\{Sender}", author.getAsMention()); // Only checking for {Sender} + + insufficientPermission.addField(customTitle, customMessage, false); + } + + channel.sendMessage(insufficientPermission.build()).queue(); + return; + } + } } } @Override - public void onGuildMemberLeave(@Nonnull GuildMemberLeaveEvent event) { + public void onGuildMemberRemove(@Nonnull GuildMemberRemoveEvent event) + { + if(!MainConfig.getMainConfig().getBoolean("un-whitelist-on-server-leave")) + return; + String discordUserToRemove = event.getMember().getId(); DiscordWhitelister.getPlugin().getLogger().info(discordUserToRemove + " left. Removing their whitelisted entries..."); - List ls = DiscordWhitelister.getRegisteredUsers(discordUserToRemove); + List ls = UserList.getRegisteredUsers(discordUserToRemove); - if(ls != null) { - - for (Object minecraftNameToRemove : ls) { + if(ls != null) + { + for (Object minecraftNameToRemove : ls) + { DiscordWhitelister.getPlugin().getLogger().info(minecraftNameToRemove.toString() + " left. Removing their whitelisted entries."); - if (DiscordWhitelister.useEasyWhitelist) { - executeServerCommand("easywl remove " + minecraftNameToRemove.toString()); + if (WhitelistedPlayers.usingEasyWhitelist) + { + ExecuteServerCommand("easywl remove " + minecraftNameToRemove.toString()); } else { - executeServerCommand("whitelist remove " + minecraftNameToRemove.toString()); + ExecuteServerCommand("whitelist remove " + minecraftNameToRemove.toString()); } } - try { - DiscordWhitelister.resetRegisteredUsers(discordUserToRemove); - } catch (IOException e) { + + try + { + UserList.resetRegisteredUsers(discordUserToRemove); + } + catch (IOException e) + { e.printStackTrace(); return; } - DiscordWhitelister.getPlugin().getLogger().info(discordUserToRemove + " left. Successfully removed their whitelisted entries."); - + DiscordWhitelister.getPlugin().getLogger().info(discordUserToRemove + " left. Successfully removed their whitelisted entries from the user list."); } - else { + else + { DiscordWhitelister.getPlugin().getLogger().warning(discordUserToRemove + " left. Could not removed their whitelisted entries as they did not whitelist through this plugin."); } } - private boolean checkWhitelistJSON(File whitelistFile, String minecraftUsername) { - boolean correctUsername = false; + public static void StartUpMemberCheck() throws IOException + { + if(!MainConfig.getMainConfig().getBoolean("un-whitelist-on-server-leave")) + return; - try { - JSONParser jsonParser = new JSONParser(); - JSONArray jsonArray = (JSONArray) jsonParser.parse(new FileReader(whitelistFile)); + // Don't attempt to remove members if not connected + if(javaDiscordAPI.getStatus() != JDA.Status.CONNECTED) + return; - for (Object object : jsonArray) { - JSONObject player = (JSONObject) object; + DiscordWhitelister.getPluginLogger().info("Checking Discord IDs for leavers..."); - String userName = (String) player.get("name"); - userName = userName.toLowerCase(); + Yaml idYaml = new Yaml(); + InputStream inputStream = new FileInputStream(UserList.getUserListFile()); - if (userName.equals(minecraftUsername)) { - correctUsername = true; + PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream); + int b = pushbackInputStream.read(); + + if(b == -1) + return; + else + pushbackInputStream.unread(b); + + Map> userObject = idYaml.load(pushbackInputStream); + + for(Map.Entry> entry : userObject.entrySet()) + { + // Check if the ID is in any guilds + boolean inGuild = false; + + // Check all guilds + for(int i = 0; i < javaDiscordAPI.getGuilds().size(); i++) + { + if(javaDiscordAPI.getGuilds().get(i).getMemberById(entry.getKey()) != null) + inGuild = true; + } + + // un-whitelist associated minecraft usernames if not in any guilds + if(!inGuild) + { + for(int i = 0; i < entry.getValue().size(); i++) + { + // un-whitelist + if(!WhitelistedPlayers.usingEasyWhitelist) + { + DiscordClient.ExecuteServerCommand("whitelist remove " + entry.getValue().get(i)); + } + else + { + DiscordClient.ExecuteServerCommand("easywl remove " + entry.getValue().get(i)); + } + + DiscordWhitelister.getPluginLogger().info("Removed " + entry.getValue().get(i) + + " from the whitelist as Discord ID: " + entry.getKey() + " has left the server."); + } + + // Clear entries in user-list + if(userObject.get(entry.getKey()) != null) + { + UserList.getUserList().set(entry.getKey(), null); + + UserList.SaveStore(); + + DiscordWhitelister.getPlugin().getLogger().info("Discord ID: " + entry.getKey() + + " left. Successfully removed their whitelisted entries from the user list."); } } - } catch (IOException | ParseException e) { + } + } + + // Find all occurrences of the target player and remove them + private static void ClearPlayerFromUserList(String targetName) + { + // Just in-case + targetName = targetName.toLowerCase(); + + // Get a list of all IDs that contain targetName - shouldn't ever really happen + List idsContainingTargetName = new LinkedList<>(); + + Yaml userYaml = new Yaml(); + + try + { + InputStream inputStream = new FileInputStream(UserList.getUserListFile()); + + // Check if input stream is empty + PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream); + int b = pushbackInputStream.read(); + + // Make sure the user list is not empty + if(b != -1) + { + pushbackInputStream.unread(b); + + Map> userListObject = userYaml.load(pushbackInputStream); + + // Search for name and Id linked to it + for(Map.Entry> entry : userListObject.entrySet()) + { + for(int i = 0; i < entry.getValue().size(); i++) + { + if(entry.getValue().get(i).equals(targetName)) + { + // Found the target name, add ID to list + idsContainingTargetName.add(entry.getKey()); + } + } + } + + // Check if we found any IDs + if(idsContainingTargetName.size() > 0) + { + DiscordWhitelister.getPluginLogger().info("Found " + idsContainingTargetName.size() + "occurrence(s) of " + targetName + " in the user list, removing..."); + + for(int i = 0; i < idsContainingTargetName.size(); i++) + { + // Get the IDs whitelisted users + List newWhitelistedUsers = UserList.getUserList().getStringList(idsContainingTargetName.get(i)); + + if(newWhitelistedUsers.size() > 1) + { + newWhitelistedUsers.remove(targetName); + UserList.getUserList().set(idsContainingTargetName.get(i), newWhitelistedUsers); + } + else + { + // Double check the 1 whitelisted user == targetName + if(newWhitelistedUsers.get(0).equals(targetName)) + UserList.getUserList().set(idsContainingTargetName.get(i), null); + } + + UserList.SaveStore(); + } + } + } + } + catch (IOException e) + { e.printStackTrace(); } - - return correctUsername; } private String minecraftUsernameToUUID(String minecraftUsername) @@ -1166,10 +1808,157 @@ public class DiscordClient extends ListenerAdapter return playerUUID; } - private void executeServerCommand(String command) + public static void ExecuteServerCommand(String command) { DiscordWhitelister.getPlugin().getServer().getScheduler().callSyncMethod(DiscordWhitelister.getPlugin(), () -> DiscordWhitelister.getPlugin().getServer().dispatchCommand( DiscordWhitelister.getPlugin().getServer().getConsoleSender(), command)); } + + private enum SenderType { CONSOLE, PLAYER, UNKNOWN } + public static void CheckAndExecuteCommand(String configInput, String playerTargetName) + { + SenderType senderType; + + // Check command sender type + if(configInput.startsWith("CONSOLE")) + senderType = SenderType.CONSOLE; + else if(configInput.startsWith("PLAYER")) + senderType = SenderType.PLAYER; + else + senderType = SenderType.UNKNOWN; + + if(senderType.equals(SenderType.UNKNOWN)) + { + DiscordWhitelister.getPluginLogger().warning("Unknown command sender type (should be one of the following: CONSOLE, PLAYER), offending line: " + configInput); + return; + } + + // Get command which is after the first : + String commandToSend = configInput.substring(configInput.indexOf(":") + 1); + // Set player name if %PLAYER% is used + final String commandToSendFinal = commandToSend.replaceAll("%PLAYER%", playerTargetName); + + if(senderType.equals(SenderType.CONSOLE)) + { + DiscordWhitelister.getPlugin().getServer().getScheduler().callSyncMethod(DiscordWhitelister.getPlugin(), + () -> DiscordWhitelister.getPlugin().getServer().dispatchCommand(DiscordWhitelister.getPlugin().getServer().getConsoleSender(), commandToSendFinal)); + } + else + { + DiscordWhitelister.getPlugin().getServer().getPlayer(playerTargetName).performCommand(commandToSendFinal); + } + } + + // use this multiple times when checking all guilds + // Accepts a single role in the form of a singleton list + public static void AssignRolesToUser(Guild targetGuild, String targetUserId, List targetRole) + { + // Check if the user is in the targetGuild + if(targetGuild.getMemberById(targetUserId) == null) + { + DiscordWhitelister.getPluginLogger().warning("User cannot be found in Guild " + targetGuild.getName() + + "(" + targetGuild.getId() + ")" +". Will not attempt to assign role(s)"); + + return; + } + + // Locate target role(s) + LinkedList rolesFound = new LinkedList<>(); + for(int i = 0; i < targetRole.size(); i++) + { + List tempFoundRoles; + + if(!DiscordWhitelister.useIdForRoles) + tempFoundRoles = targetGuild.getRolesByName(targetRole.get(i), false); + else + tempFoundRoles = Collections.singletonList(targetGuild.getRoleById(targetRole.get(i))); + + if(tempFoundRoles.size() > 0) + { + rolesFound.addAll(tempFoundRoles); + } + else + { + String discordUserName = targetGuild.getMemberById(targetUserId).getEffectiveName(); + DiscordWhitelister.getPluginLogger().warning("Failed to assign role " + targetRole.get(i) + + " to user " + discordUserName + "(" + targetUserId + ")" + " as it could not be found in " + + targetGuild.getName() + "(" + targetGuild.getId() + ")"); + } + } + + // Check if any roles were found + if(rolesFound.size() > 0) + { + // Assign the roles + for(int i = 0; i < rolesFound.size(); i++) + { + targetGuild.addRoleToMember(targetGuild.getMemberById(targetUserId), rolesFound.get(i)).queue(); + } + } + } + + public static void RemoveRolesFromUser(Guild targetGuild, String targetUserId, List targetRole) + { + // Check if the user is in the targetGuild + if(targetGuild.getMemberById(targetUserId) == null) + { + DiscordWhitelister.getPluginLogger().warning("User cannot be found in Guild " + targetGuild.getName() + + "(" + targetGuild.getId() + ")" +". Will not attempt to remove role(s)"); + + return; + } + + // Locate target role(s) + LinkedList rolesFound = new LinkedList<>(); + for(int i = 0; i < targetRole.size(); i++) + { + List tempFoundRoles; + + if(!DiscordWhitelister.useIdForRoles) + tempFoundRoles = targetGuild.getRolesByName(targetRole.get(i), false); + else + tempFoundRoles = Collections.singletonList(targetGuild.getRoleById(targetRole.get(i))); + + if(tempFoundRoles.size() > 0) + { + rolesFound.addAll(tempFoundRoles); + } + else + { + String discordUserName = targetGuild.getMemberById(targetUserId).getEffectiveName(); + DiscordWhitelister.getPluginLogger().warning("Failed to remove role " + targetRole.get(i) + + " from user " + discordUserName + "(" + targetUserId + ")" + " as it could not be found in " + + targetGuild.getName() + "(" + targetGuild.getId() + ")"); + } + } + + // Check if any roles were found + if(rolesFound.size() > 0) + { + // Assign the roles + for(int i = 0; i < rolesFound.size(); i++) + { + targetGuild.removeRoleFromMember(targetGuild.getMemberById(targetUserId), rolesFound.get(i)).queue(); + } + } + } + + // TODO: improve, not go through console commands + // For ultra perms + public static void AssignPermsToUser(String targetPlayerName, List permsToAssign) + { + for(int i = 0; i < permsToAssign.size(); i++) + { + DiscordClient.ExecuteServerCommand("upc addPlayerPermission " + targetPlayerName + " " + permsToAssign.get(i)); + } + } + + public static void RemovePermsFromUser(String targetPlayerName, List permsToRemove) + { + for(int i = 0; i < permsToRemove.size(); i++) + { + DiscordClient.ExecuteServerCommand("upc removePlayerPermission " + targetPlayerName + " " + permsToRemove.get(i)); + } + } } diff --git a/src/main/java/uk/co/angrybee/joe/DiscordWhitelister.java b/src/main/java/uk/co/angrybee/joe/DiscordWhitelister.java index 1a34e70..994f6cd 100755 --- a/src/main/java/uk/co/angrybee/joe/DiscordWhitelister.java +++ b/src/main/java/uk/co/angrybee/joe/DiscordWhitelister.java @@ -4,48 +4,45 @@ import org.bukkit.Server; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import uk.co.angrybee.joe.Commands.CommandAbout; import uk.co.angrybee.joe.Commands.CommandReload; import uk.co.angrybee.joe.Commands.CommandStatus; -import uk.co.angrybee.joe.Configs.CustomMessagesConfig; -import uk.co.angrybee.joe.Configs.CustomPrefixConfig; -import uk.co.angrybee.joe.Configs.MainConfig; +import uk.co.angrybee.joe.Configs.*; import uk.co.angrybee.joe.Events.JoinLeaveEvents; +import uk.co.angrybee.joe.Events.OnBanEvent; +import uk.co.angrybee.joe.Events.OnWhitelistEvents; +import uk.co.angrybee.joe.Stores.InGameRemovedList; +import uk.co.angrybee.joe.Stores.RemovedList; +import uk.co.angrybee.joe.Stores.UserList; +import uk.co.angrybee.joe.Stores.WhitelistedPlayers; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; import java.util.logging.Logger; public class DiscordWhitelister extends JavaPlugin { - private static File userListFile; - private static File removedListFile; - - private static FileConfiguration userList; - private static FileConfiguration removedList; - - // easy whitelist - public static Plugin easyWhitelist; - public static String botToken; private static boolean configCreated = false; - private static boolean userListCreated = false; - private static boolean removedListCreated = false; - public static boolean useEasyWhitelist = false; public static boolean useCustomMessages = false; public static boolean useIdForRoles = false; public static boolean useCustomPrefixes = false; public static boolean showPlayerSkin = true; - public static boolean addInGameRemovesToList = true; public static boolean showVanishedPlayersInCount = false; + public static boolean useInGameAddRemoves = true; + public static boolean useOnBanEvents = true; + public static boolean useUltraPerms = false; + public static boolean useOnWhitelistCommands = false; public static boolean botEnabled; + public static String[] bannedRoles; + private static JavaPlugin thisPlugin; private static Server thisServer; private static Logger pluginLogger; @@ -71,67 +68,41 @@ public class DiscordWhitelister extends JavaPlugin pluginLogger.severe("Discord Client failed to initialize, please check if your config file is valid"); } + // Check for leavers if enabled + if(MainConfig.getMainConfig().getBoolean("un-whitelist-on-server-leave")) + { + try + { + DiscordClient.StartUpMemberCheck(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + this.getCommand("discordwhitelister").setExecutor(new CommandStatus()); this.getCommand("discordwhitelisterabout").setExecutor(new CommandAbout()); this.getCommand("discordwhitelisterreload").setExecutor(new CommandReload()); } + @Override + public void onDisable() + { + DiscordClient.javaDiscordAPI.shutdownNow(); + } + public static JavaPlugin getPlugin() { return thisPlugin; } - public static FileConfiguration getWhitelisterBotConfig() { return MainConfig.getMainConfig(); } - - public static FileConfiguration getUserList() - { - return userList; - } - - public static File getUserListFile() - { - return userListFile; - } - - public static FileConfiguration getRemovedList() { return removedList; } - - public static File getRemovedListFile() - { - return removedListFile; - } - public static FileConfiguration getCustomMessagesConfig() { return CustomMessagesConfig.getCustomMessagesConfig(); } public static Logger getPluginLogger() { return pluginLogger; } - public static List getRegisteredUsers(String userId) { return userList.getList(userId); } - - public static int getRegisteredUsersCount(String userId) { - try { - return getRegisteredUsers(userId).size(); - } catch(NullPointerException ex) { - return 0; - } - } - public static boolean getUseCustomPrefixes() { return useCustomPrefixes; } - public static void addRegisteredUser(String userId, String userToAdd) throws IOException { - List x = getRegisteredUsers(userId); - List newList = new ArrayList<>(); - for (Object o: x) { - newList.add(o.toString()); - } - newList.add(userToAdd); - getUserList().set(userId, newList); - getUserList().save(getUserListFile().getPath()); - } - - public static void resetRegisteredUsers(String userId) throws IOException { - getUserList().set(userId, new ArrayList<>()); - getUserList().save(getUserListFile().getPath()); - } - public static void addVanishedPlayer() { vanishedPlayersCount++; } public static void removeVanishedPlayer() { vanishedPlayersCount--; } @@ -142,23 +113,41 @@ public class DiscordWhitelister extends JavaPlugin public static int InitBot(boolean firstInit) { - userList = new YamlConfiguration(); - removedList = new YamlConfiguration(); - if(firstInit) vanishedPlayersCount = 0; ConfigSetup(); - botToken = getWhitelisterBotConfig().getString("discord-bot-token"); - botEnabled = getWhitelisterBotConfig().getBoolean("bot-enabled"); - showPlayerSkin = getWhitelisterBotConfig().getBoolean("show-player-skin-on-whitelist"); + botToken = MainConfig.getMainConfig().getString("discord-bot-token"); + botEnabled = MainConfig.getMainConfig().getBoolean("bot-enabled"); + showPlayerSkin = MainConfig.getMainConfig().getBoolean("show-player-skin-on-whitelist"); configCreated = MainConfig.configCreated; showVanishedPlayersInCount = MainConfig.getMainConfig().getBoolean("show-vanished-players-in-player-count"); + useInGameAddRemoves = MainConfig.getMainConfig().getBoolean("add-in-game-adds-and-removes-to-list"); + useOnBanEvents = MainConfig.getMainConfig().getBoolean("use-on-ban-events"); + // Check for UltraPerms first + if(MainConfig.getMainConfig().getBoolean("assign-perms-with-ultra-perms")) + { + if(DiscordWhitelister.getPlugin().getServer().getPluginManager().getPlugin("UltraPermissions") != null) + { + useUltraPerms = true; + DiscordWhitelister.getPluginLogger().info("Ultra Permissions found!"); + } + else + { + DiscordWhitelister.getPluginLogger().warning("Ultra Permissions was not found but is enabled in the config. Doing nothing..."); + useUltraPerms = false; + } + } - DiscordClient.whitelistAddPrefix = CustomPrefixConfig.getCustomPrefixesConfig().getString("whitelist-add-prefix"); - DiscordClient.whitelistRemovePrefix = CustomPrefixConfig.getCustomPrefixesConfig().getString("whitelist-remove-prefix"); + if(MainConfig.getMainConfig().getBoolean("use-on-whitelist-commands")) + useOnWhitelistCommands = true; + + DiscordClient.whitelistAddPrefix = CustomPrefixConfig.getCustomPrefixesConfig().getString("whitelist-add-prefix").toLowerCase(); + DiscordClient.whitelistRemovePrefix = CustomPrefixConfig.getCustomPrefixesConfig().getString("whitelist-remove-prefix").toLowerCase(); + DiscordClient.clearNamePrefix = CustomPrefixConfig.getCustomPrefixesConfig().getString("clear-name-prefix").toLowerCase(); + DiscordClient.clearBanPrefix = CustomPrefixConfig.getCustomPrefixesConfig().getString("clear-ban-prefix").toLowerCase(); if(!botEnabled) { @@ -172,58 +161,61 @@ public class DiscordWhitelister extends JavaPlugin { pluginLogger.info("Initializing Discord client..."); - useIdForRoles = getWhitelisterBotConfig().getBoolean("use-id-for-roles"); + // TODO: below role section could be moved to DiscordClient class + useIdForRoles = MainConfig.getMainConfig().getBoolean("use-id-for-roles"); // set add & remove roles - DiscordClient.allowedToAddRemoveRoles = new String[getWhitelisterBotConfig().getList("add-remove-roles").size()]; + DiscordClient.allowedToAddRemoveRoles = new String[MainConfig.getMainConfig().getList("add-remove-roles").size()]; for(int roles = 0; roles < DiscordClient.allowedToAddRemoveRoles.length; ++roles) { - DiscordClient.allowedToAddRemoveRoles[roles] = getWhitelisterBotConfig().getList("add-remove-roles").get(roles).toString(); + DiscordClient.allowedToAddRemoveRoles[roles] = MainConfig.getMainConfig().getList("add-remove-roles").get(roles).toString(); } // set add roles - DiscordClient.allowedToAddRoles = new String[getWhitelisterBotConfig().getList("add-roles").size()]; + DiscordClient.allowedToAddRoles = new String[MainConfig.getMainConfig().getList("add-roles").size()]; for(int roles = 0; roles < DiscordClient.allowedToAddRoles.length; ++roles) { - DiscordClient.allowedToAddRoles[roles] = getWhitelisterBotConfig().getList("add-roles").get(roles).toString(); + DiscordClient.allowedToAddRoles[roles] = MainConfig.getMainConfig().getList("add-roles").get(roles).toString(); } // set limited add roles - DiscordClient.allowedToAddLimitedRoles = new String[getWhitelisterBotConfig().getList("limited-add-roles").size()]; + DiscordClient.allowedToAddLimitedRoles = new String[MainConfig.getMainConfig().getList("limited-add-roles").size()]; for(int roles = 0; roles < DiscordClient.allowedToAddLimitedRoles.length; ++roles) { - DiscordClient.allowedToAddLimitedRoles[roles] = getWhitelisterBotConfig().getList("limited-add-roles").get(roles).toString(); + DiscordClient.allowedToAddLimitedRoles[roles] = MainConfig.getMainConfig().getList("limited-add-roles").get(roles).toString(); } - // easy whitelist check - if(getWhitelisterBotConfig().getBoolean("use-easy-whitelist")) + // Get banned roles + if(useOnBanEvents) { - pluginLogger.info("Checking for Easy Whitelist..."); - if(thisServer.getPluginManager().getPlugin("EasyWhitelist") != null) + List tempBannedRoles = MainConfig.getMainConfig().getStringList("banned-roles"); + bannedRoles = new String[tempBannedRoles.size()]; + for(int i = 0; i < tempBannedRoles.size(); i++) { - pluginLogger.info("Easy Whitelist found! Will use over default whitelist command."); - easyWhitelist = thisServer.getPluginManager().getPlugin("EasyWhitelist"); - useEasyWhitelist = true; - } - else - { - pluginLogger.warning("Easy Whitelist was not found but is enabled in the config. " + - "Falling back to default whitelist command."); + bannedRoles[i] = tempBannedRoles.get(i); } } + // Allowed to clear name roles + DiscordClient.allowedToClearNamesRoles = new String[MainConfig.getMainConfig().getStringList("clear-command-roles").size()]; + for(int roles = 0; roles < DiscordClient.allowedToClearNamesRoles.length; roles++) + { + DiscordClient.allowedToClearNamesRoles[roles] = MainConfig.getMainConfig().getStringList("clear-command-roles").get(roles); + } + // Custom messages check - useCustomMessages = getWhitelisterBotConfig().getBoolean("use-custom-messages"); - useCustomPrefixes = getWhitelisterBotConfig().getBoolean("use-custom-prefixes"); + useCustomMessages = MainConfig.getMainConfig().getBoolean("use-custom-messages"); + useCustomPrefixes = MainConfig.getMainConfig().getBoolean("use-custom-prefixes"); int initSuccess = DiscordClient.InitializeClient(botToken); if(initSuccess == 1) return 1; + // No need for an if here statement anymore as this code will not run if the client has not been initialized // Only attempt to set player count if the bot successfully initialized - if(getWhitelisterBotConfig().getBoolean("show-player-count")) + if(MainConfig.getMainConfig().getBoolean("show-player-count")) { // Register events if enabled thisServer.getPluginManager().registerEvents(new JoinLeaveEvents(), thisPlugin); @@ -232,6 +224,14 @@ public class DiscordWhitelister extends JavaPlugin DiscordClient.SetPlayerCountStatus(getOnlineUsers()); } + // Register whitelist events if enabled + if(useInGameAddRemoves) + thisServer.getPluginManager().registerEvents(new OnWhitelistEvents(), thisPlugin); + + // Register ban events if enabled + if(useOnBanEvents) + thisServer.getPluginManager().registerEvents(new OnBanEvent(), thisPlugin); + return 0; } @@ -240,88 +240,19 @@ public class DiscordWhitelister extends JavaPlugin public static void ConfigSetup() { - File dataFolder = thisPlugin.getDataFolder(); - Logger pluginLogger = thisPlugin.getLogger(); - // Run this first, as it creates the root folder if it does not exist MainConfig.ConfigSetup(); + CustomPrefixConfig.ConfigSetup(); CustomMessagesConfig.ConfigSetup(); + PermissionsConfig.ConfigSetup(); + OnWhitelistCommandsConfig.ConfigSetup(); - userListFile = new File(dataFolder, "user-list.yml"); - removedListFile = new File(dataFolder, "removed-list.yml"); + // Init Stores + UserList.StoreSetup(); + InGameRemovedList.StoreSetup(); + RemovedList.StoreSetup(); - if(!userListFile.exists()) - { - try - { - userListFile.createNewFile(); - } - catch (IOException e) - { - e.printStackTrace(); - } - - pluginLogger.info("User list created at: " + userListFile.getPath()); - userListCreated = true; - } - - try - { - getUserList().load(userListFile); - } - catch (IOException | InvalidConfigurationException e) - { - e.printStackTrace(); - } - - if(!removedListFile.exists()) - { - try - { - removedListFile.createNewFile(); - } - catch (IOException e) - { - e.printStackTrace(); - } - - pluginLogger.info("Removed list created at: " + removedListFile.getPath()); - removedListCreated = true; - } - - try - { - getRemovedList().load(removedListFile); - } - catch (IOException | InvalidConfigurationException e) - { - e.printStackTrace(); - } - - if(userListCreated) - { - try - { - getUserList().save(userListFile.getPath()); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - if(removedListCreated) - { - //getRemovedList().set("minecraftUsername", "discordRemoverID"); - try - { - getRemovedList().save(removedListFile.getPath()); - } - catch (IOException e) - { - e.printStackTrace(); - } - } + WhitelistedPlayers.Setup(); } } diff --git a/src/main/java/uk/co/angrybee/joe/Events/OnBanEvent.java b/src/main/java/uk/co/angrybee/joe/Events/OnBanEvent.java new file mode 100644 index 0000000..67fd21e --- /dev/null +++ b/src/main/java/uk/co/angrybee/joe/Events/OnBanEvent.java @@ -0,0 +1,149 @@ +package uk.co.angrybee.joe.Events; + +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.yaml.snakeyaml.Yaml; +import uk.co.angrybee.joe.Configs.MainConfig; +import uk.co.angrybee.joe.Configs.PermissionsConfig; +import uk.co.angrybee.joe.DiscordClient; +import uk.co.angrybee.joe.DiscordWhitelister; +import uk.co.angrybee.joe.Stores.InGameRemovedList; +import uk.co.angrybee.joe.Stores.UserList; +import uk.co.angrybee.joe.Stores.WhitelistedPlayers; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + + +public class OnBanEvent implements Listener +{ + @EventHandler + public void onCommandBan(PlayerCommandPreprocessEvent e) throws IOException + { + // Context + Player commandCaller = e.getPlayer(); + String message = e.getMessage().toLowerCase(); + +// // Check just in case? +// if(!DiscordWhitelister.useOnBanEvents) +// return; + + // Check if player is using the ban command + if(!message.startsWith("/ban")) + return; + + // Check if the player has permission to use the ban command before proceeding + // Do not bother checking if the player can ban ips as we get no useful information from it + if(!commandCaller.hasPermission("bukkit.command.ban.player")) + return; + + String banTarget = message.substring("/ban".length() + 1).toLowerCase(); + // Remove ban reason if there is one + if(banTarget.contains(" ")) + { + banTarget = banTarget.substring(0, banTarget.indexOf(" ")); + } + + // Check if there is a name to query + if(banTarget.equals("")) + return; + + // Check if the player has ever joined the server or is on the whitelist + Server server = DiscordWhitelister.getPlugin().getServer(); + if(!server.getOnlinePlayers().contains(banTarget) || !server.getOnlinePlayers().contains(banTarget)) + { + if(!WhitelistedPlayers.usingEasyWhitelist && !WhitelistedPlayers.CheckForPlayer(banTarget) + || WhitelistedPlayers.usingEasyWhitelist && !WhitelistedPlayers.CheckForPlayerEasyWhitelist(banTarget)) + { + DiscordWhitelister.getPluginLogger().info(commandCaller.getName() + " is attempting to ban player with the name " + banTarget + + " but the user is not on the whitelist nor have they joined the server; doing nothing..."); + return; + } + } + + // Assign initial ban target to in-game removed list + InGameRemovedList.AddUserToStore(banTarget, commandCaller.getDisplayName()); + + // Check if the player is whitelisted + if(!WhitelistedPlayers.usingEasyWhitelist && WhitelistedPlayers.CheckForPlayer(banTarget) + || WhitelistedPlayers.usingEasyWhitelist && WhitelistedPlayers.CheckForPlayerEasyWhitelist(banTarget)) + { + Boolean idFound = false; + String targetDiscordId = ""; + List targetWhitelistedPlayers = Collections.emptyList(); + + // Find the Discord Id linked to the whitelisted player + Yaml userYaml = new Yaml(); + + InputStream inputStream = new FileInputStream(UserList.getUserListFile()); + + Map> testObject = userYaml.load(inputStream); + + for(Map.Entry> entry : testObject.entrySet()) + { + for(int i = 0; i < entry.getValue().size(); i++) + { + if(entry.getValue().get(i).equals(banTarget)) + { + // Found the ban target, assign the corresponding Discord id + targetDiscordId = entry.getKey(); + targetWhitelistedPlayers = entry.getValue(); + idFound = true; + } + } + } + + if(idFound) + { + // Remove whitelisted players associated with the discord id + for(int i = 0; i < targetWhitelistedPlayers.size(); i++) + { + if(!WhitelistedPlayers.usingEasyWhitelist) + { + DiscordClient.ExecuteServerCommand("whitelist remove " + targetWhitelistedPlayers.get(i)); + } + else + { + DiscordClient.ExecuteServerCommand("easywl remove " + targetWhitelistedPlayers.get(i)); + } + + DiscordWhitelister.getPluginLogger().info("Removed " + targetWhitelistedPlayers.get(i) + + " from the whitelist as they were added by Discord Id: " + targetDiscordId); + + // Add username to the in-game removed list + InGameRemovedList.AddUserToStore(targetWhitelistedPlayers.get(i), commandCaller.getDisplayName()); + } + + // Remove the users whitelisted players from the list + UserList.getUserList().set(targetDiscordId, null); + + // Remove perms on ban if enabled + if(DiscordWhitelister.useUltraPerms) + DiscordClient.RemovePermsFromUser(banTarget, PermissionsConfig.getPermissionsConfig().getStringList("perms-on-whitelist")); + + UserList.SaveStore(); + + // Find all servers bot is in, assign & remove roles + for(int i = 0; i < DiscordClient.javaDiscordAPI.getGuilds().size(); i++) + { + // Remove the whitelisted role(s) + DiscordClient.RemoveRolesFromUser(DiscordClient.javaDiscordAPI.getGuilds().get(i), targetDiscordId, Arrays.asList(DiscordClient.whitelistedRoleNames)); + // Add the banned role(s) + DiscordClient.AssignRolesToUser(DiscordClient.javaDiscordAPI.getGuilds().get(i), targetDiscordId, (List) MainConfig.getMainConfig().get("banned-roles")); + } + } + else + { + DiscordWhitelister.getPluginLogger().warning(banTarget + " does not have a linked Discord Id; cannot assign roles!"); + } + } + } +} diff --git a/src/main/java/uk/co/angrybee/joe/Events/OnWhitelistEvents.java b/src/main/java/uk/co/angrybee/joe/Events/OnWhitelistEvents.java index c898313..1024211 100644 --- a/src/main/java/uk/co/angrybee/joe/Events/OnWhitelistEvents.java +++ b/src/main/java/uk/co/angrybee/joe/Events/OnWhitelistEvents.java @@ -3,26 +3,37 @@ package uk.co.angrybee.joe.Events; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; import uk.co.angrybee.joe.DiscordWhitelister; +import uk.co.angrybee.joe.Stores.InGameRemovedList; +import uk.co.angrybee.joe.Stores.RemovedList; +import uk.co.angrybee.joe.Stores.WhitelistedPlayers; + +import java.io.File; // Checks for whitelist removes in-game, so player's cannot use the bot to add them back without an admin/staff member with higher permissions public class OnWhitelistEvents implements Listener { private enum CommandContext { VANILLA_ADD, EASYWL_ADD, VANILLA_REMOVE, EASYWL_REMOVE } + // TODO: incorporate this into the checkWhitelistJSON function + private static final File whitelistFile = (new File(".", "whitelist.json")); + @EventHandler - public void PlayerCommandPreprocessEvent(Player commandCaller, String message) + public void onCommandPreprocess(PlayerCommandPreprocessEvent event) { // Initial check CommandContext commandContext; + Player commandCaller = event.getPlayer(); + String message = event.getMessage(); - if(message.startsWith("!whitelist add")) + if(message.startsWith("/whitelist add")) commandContext = CommandContext.VANILLA_ADD; - else if(message.startsWith("!easywl add")) + else if(message.startsWith("/easywl add")) commandContext = CommandContext.EASYWL_ADD; - else if(message.startsWith("!whitelist remove")) + else if(message.startsWith("/whitelist remove")) commandContext = CommandContext.VANILLA_REMOVE; - else if(message.startsWith("!easywl remove")) + else if(message.startsWith("/easywl remove")) commandContext = CommandContext.EASYWL_REMOVE; else return; @@ -39,27 +50,58 @@ public class OnWhitelistEvents implements Listener // Determine what command to check + String targetName = ""; + // Check for adds to remove player's off the removed list (if they are on it) - if(commandContext.equals(CommandContext.VANILLA_ADD) && !DiscordWhitelister.useEasyWhitelist) + if(commandContext.equals(CommandContext.VANILLA_ADD) && !WhitelistedPlayers.usingEasyWhitelist) { - // TODO - // Check removed-list.yml, remove username from there if it exists - // Check in-game removed list when created and remove from there if it exists - // Log removal of name from list if it existed + targetName = message.substring("/whitelist add".length() + 1).toLowerCase(); + ClearPlayerFromRemovedLists(targetName, commandCaller); } - else if(commandContext.equals(CommandContext.EASYWL_ADD) && DiscordWhitelister.useEasyWhitelist) + else if(commandContext.equals(CommandContext.EASYWL_ADD) && WhitelistedPlayers.usingEasyWhitelist) { + targetName = message.substring("/easywl add".length() + 1).toLowerCase(); + ClearPlayerFromRemovedLists(targetName, commandCaller); + } + else if(commandContext.equals(CommandContext.VANILLA_REMOVE) && !WhitelistedPlayers.usingEasyWhitelist) + { + targetName = message.substring("/whitelist remove".length() + 1).toLowerCase(); + if(WhitelistedPlayers.CheckForPlayer(targetName)) + { + InGameRemovedList.AddUserToStore(targetName, commandCaller.getName()); + DiscordWhitelister.getPluginLogger().info(commandCaller.getName() + " has added " + targetName + " to the in-game removed list"); + } } - else if(commandContext.equals(CommandContext.VANILLA_REMOVE) && !DiscordWhitelister.useEasyWhitelist) - { - // TODO - // Check if the player is in the whitelist as this runs before the command is executed - // Add player to in-game removed list and the players' name that removed it - } - else if(commandContext.equals(CommandContext.EASYWL_REMOVE) && DiscordWhitelister.useEasyWhitelist) + else if(commandContext.equals(CommandContext.EASYWL_REMOVE) && WhitelistedPlayers.usingEasyWhitelist) { + targetName = message.substring("/easywl remove".length() + 1).toLowerCase(); + if(WhitelistedPlayers.CheckForPlayerEasyWhitelist(targetName)) + { + InGameRemovedList.AddUserToStore(targetName, commandCaller.getName()); + DiscordWhitelister.getPluginLogger().info(commandCaller.getName() + " has added " + targetName + " to the in-game removed list"); + } + } + } + + private static void ClearPlayerFromRemovedLists(String playerName, Player commandCaller) + { + if(RemovedList.CheckStoreForPlayer(playerName)) + { + DiscordWhitelister.getPluginLogger().info(commandCaller.getName() + " is attempting to add " + playerName + ". Removing " + playerName + + " from removed-list.yml"); + RemovedList.getRemovedPlayers().set(playerName, null); + + // Save changes + RemovedList.SaveStore(); + } + + if(InGameRemovedList.CheckStoreForPlayer(playerName)) + { + InGameRemovedList.RemoveUserFromStore(playerName); + DiscordWhitelister.getPluginLogger().info(commandCaller.getName() + " is attempting to add " + playerName + ". Removing " + playerName + + " from in-game-removed-list.yml"); } } } diff --git a/src/main/java/uk/co/angrybee/joe/Events/ShutdownEvents.java b/src/main/java/uk/co/angrybee/joe/Events/ShutdownEvents.java new file mode 100644 index 0000000..836aceb --- /dev/null +++ b/src/main/java/uk/co/angrybee/joe/Events/ShutdownEvents.java @@ -0,0 +1,30 @@ +package uk.co.angrybee.joe.Events; + +import net.dv8tion.jda.api.events.ShutdownEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.requests.CloseCode; +import uk.co.angrybee.joe.DiscordClient; +import uk.co.angrybee.joe.DiscordWhitelister; + +public class ShutdownEvents extends ListenerAdapter +{ + @Override + public void onShutdown(ShutdownEvent shutdownEvent) + { + CheckIntents(shutdownEvent.getCloseCode()); + } + + // Check for the 'SERVER MEMBERS INTENT' and inform users if not enabled + private void CheckIntents(CloseCode closeCode) + { + if(closeCode == null) + return; + + if(closeCode == CloseCode.DISALLOWED_INTENTS) + { + DiscordWhitelister.getPluginLogger().severe("\u001B[31m" + "Cannot connect as this bot is not eligible to request the privileged intent 'GUILD_MEMBERS'" + "\u001B[0m"); + DiscordWhitelister.getPluginLogger().severe( "\u001B[31m" + "To fix this, please enable 'SERVER MEMBERS INTENT' located " + + "at https://discord.com/developers/applications -> the application you're using to run this bot -> the button called 'bot' on the left" + "\u001B[0m"); + } + } +} diff --git a/src/main/java/uk/co/angrybee/joe/Stores/InGameRemovedList.java b/src/main/java/uk/co/angrybee/joe/Stores/InGameRemovedList.java new file mode 100644 index 0000000..799e810 --- /dev/null +++ b/src/main/java/uk/co/angrybee/joe/Stores/InGameRemovedList.java @@ -0,0 +1,104 @@ +package uk.co.angrybee.joe.Stores; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import uk.co.angrybee.joe.DiscordWhitelister; + +import java.io.File; +import java.io.IOException; + +// Stores removed players that were removed in-game +// in-game-removed-list.yml +public class InGameRemovedList +{ + private static File removePlayersFile; + private static FileConfiguration removedPlayersConfig; + + public static FileConfiguration getRemovedPlayers() { return removedPlayersConfig; } + + private static boolean storeCreated = false; + + public static void StoreSetup() + { + removePlayersFile = new File(DiscordWhitelister.getPlugin().getDataFolder(), "in-game-removed-list.yml"); + removedPlayersConfig = new YamlConfiguration(); + + if(!removePlayersFile.exists()) + CreateStore(); + + LoadStore(); + SaveStore(); + } + + private static void CreateStore() + { + try + { + removePlayersFile.createNewFile(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private static void LoadStore() + { + try + { + removedPlayersConfig.load(removePlayersFile); + } + catch (IOException | InvalidConfigurationException e) + { + e.printStackTrace(); + } + } + + public static void SaveStore() + { + try + { + removedPlayersConfig.save(removePlayersFile.getPath()); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + public static void AddUserToStore(String nameToAdd, String commandIssuer) + { + if(removedPlayersConfig.get(nameToAdd) != null) + { + // Already in store, notify in console and update commandIssuer + String oldCommandIssuer = removedPlayersConfig.getString(nameToAdd); + DiscordWhitelister.getPluginLogger().warning(nameToAdd + " is already in the in-game removed list. Updating commandIssuer from " + + oldCommandIssuer + " to " + commandIssuer); + } + + removedPlayersConfig.set(nameToAdd, commandIssuer); + SaveStore(); + } + + public static void RemoveUserFromStore(String nameToRemove) + { + if(removedPlayersConfig.get(nameToRemove) != null) + { + removedPlayersConfig.set(nameToRemove, null); + SaveStore(); + } + else // Shouldn't ever happen + { + DiscordWhitelister.getPluginLogger().warning("Tried to remove " + nameToRemove + " from in-game-removed-list.yml, but " + + nameToRemove + " could not be found, doing nothing..."); + } + } + + // Returns true if the player is in the store/list + public static boolean CheckStoreForPlayer(String nameToCheck) + { + LoadStore(); + return removedPlayersConfig.get(nameToCheck) != null; + } +} diff --git a/src/main/java/uk/co/angrybee/joe/Stores/RemovedList.java b/src/main/java/uk/co/angrybee/joe/Stores/RemovedList.java new file mode 100644 index 0000000..a2ad723 --- /dev/null +++ b/src/main/java/uk/co/angrybee/joe/Stores/RemovedList.java @@ -0,0 +1,76 @@ +package uk.co.angrybee.joe.Stores; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import uk.co.angrybee.joe.DiscordWhitelister; + +import java.io.File; +import java.io.IOException; + +//getRemovedList().set("minecraftUsername", "discordRemoverID"); + +// Stores removed players that were removed through Discord +// removed-list.yml +public class RemovedList +{ + private static File removePlayersFile; + private static FileConfiguration removedPlayersConfig; + + public static FileConfiguration getRemovedPlayers() { return removedPlayersConfig; } + + public static void StoreSetup() + { + removePlayersFile = new File(DiscordWhitelister.getPlugin().getDataFolder(), "removed-list.yml"); + removedPlayersConfig = new YamlConfiguration(); + + if(!removePlayersFile.exists()) + CreateStore(); + + LoadStore(); + SaveStore(); + } + + private static void CreateStore() + { + try + { + removePlayersFile.createNewFile(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private static void LoadStore() + { + try + { + removedPlayersConfig.load(removePlayersFile); + } + catch (IOException | InvalidConfigurationException e) + { + e.printStackTrace(); + } + } + + public static void SaveStore() + { + try + { + removedPlayersConfig.save(removePlayersFile.getPath()); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + // Returns true if the player is in the store/list + public static boolean CheckStoreForPlayer(String nameToCheck) + { + LoadStore(); + return removedPlayersConfig.get(nameToCheck) != null; + } +} diff --git a/src/main/java/uk/co/angrybee/joe/Stores/RemovedPlayersStore.java b/src/main/java/uk/co/angrybee/joe/Stores/RemovedPlayersStore.java deleted file mode 100644 index 367474e..0000000 --- a/src/main/java/uk/co/angrybee/joe/Stores/RemovedPlayersStore.java +++ /dev/null @@ -1,6 +0,0 @@ -package uk.co.angrybee.joe.Stores; - -// Stores removed players that were removed in-game -public class RemovedPlayersStore -{ -} diff --git a/src/main/java/uk/co/angrybee/joe/Stores/UserList.java b/src/main/java/uk/co/angrybee/joe/Stores/UserList.java new file mode 100644 index 0000000..ee01d2f --- /dev/null +++ b/src/main/java/uk/co/angrybee/joe/Stores/UserList.java @@ -0,0 +1,106 @@ +package uk.co.angrybee.joe.Stores; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import uk.co.angrybee.joe.DiscordWhitelister; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +// user-list.yml +public class UserList +{ + private static File userListFile; + private static FileConfiguration userList; + + public static File getUserListFile() { return userListFile; } + public static FileConfiguration getUserList() + { + return userList; + } + public static List getRegisteredUsers(String userId) { return userList.getList(userId); } + + public static void StoreSetup() + { + userListFile = new File(DiscordWhitelister.getPlugin().getDataFolder(), "user-list.yml"); + userList = new YamlConfiguration(); + + if(!userListFile.exists()) + CreateStore(); + + LoadStore(); + SaveStore(); + } + + private static void CreateStore() + { + try + { + userListFile.createNewFile(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private static void LoadStore() + { + try + { + userList.load(userListFile); + } + catch (IOException | InvalidConfigurationException e) + { + e.printStackTrace(); + } + } + + public static void SaveStore() + { + try + { + userList.save(userListFile.getPath()); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + public static int getRegisteredUsersCount(String userId) + { + try + { + return getRegisteredUsers(userId).size(); + } + catch(NullPointerException e) + { + return 0; + } + } + + public static void addRegisteredUser(String userId, String userToAdd) throws IOException + { + List x = getRegisteredUsers(userId); + List newList = new ArrayList<>(); + + for (Object o: x) + { + newList.add(o.toString()); + } + + newList.add(userToAdd); + userList.set(userId, newList); + SaveStore(); + } + + public static void resetRegisteredUsers(String userId) throws IOException + { + getUserList().set(userId, null); + SaveStore(); + } +} diff --git a/src/main/java/uk/co/angrybee/joe/Stores/WhitelistedPlayers.java b/src/main/java/uk/co/angrybee/joe/Stores/WhitelistedPlayers.java new file mode 100644 index 0000000..b1e1323 --- /dev/null +++ b/src/main/java/uk/co/angrybee/joe/Stores/WhitelistedPlayers.java @@ -0,0 +1,100 @@ +package uk.co.angrybee.joe.Stores; + +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; +import uk.co.angrybee.joe.Configs.MainConfig; +import uk.co.angrybee.joe.DiscordWhitelister; + +import java.io.File; +import java.io.IOException; +import java.util.logging.Logger; + +// For accessing whitelisted players +public class WhitelistedPlayers +{ + private static Plugin easyWhitelist; + private static FileConfiguration easyWhitelistPlayers; + + private static final Server server = DiscordWhitelister.getPlugin().getServer(); + private static final PluginManager pluginManager = server.getPluginManager(); + private static final Logger pluginLogger = DiscordWhitelister.getPluginLogger(); + + public static boolean usingEasyWhitelist; + + public static void Setup() + { + // Check if we are using EasyWhitelist + if(MainConfig.getMainConfig().getBoolean("use-easy-whitelist")) + GetEasyWhitelist(); + + if(usingEasyWhitelist) + { + try + { + easyWhitelistPlayers = new YamlConfiguration(); + easyWhitelistPlayers.load(new File(easyWhitelist.getDataFolder(), "config.yml")); + } + catch (IOException | InvalidConfigurationException e) + { + pluginLogger.severe("Failed to load the EasyWhitelist file, reverting back to vanilla whitelist command"); + usingEasyWhitelist = false; + e.printStackTrace(); + } + } + } + + private static void GetEasyWhitelist() + { + if(pluginManager.getPlugin("EasyWhitelist") != null) + { + pluginLogger.info("Easy Whitelist found; will use over default whitelist command"); + easyWhitelist = pluginManager.getPlugin("EasyWhitelist"); + usingEasyWhitelist = true; + } + else + { + usingEasyWhitelist = false; // Define this for config hot reloads + pluginLogger.warning("Easy Whitelist was not found but is enabled in the config. " + + "Falling back to default whitelist command"); + } + } + + public static boolean CheckForPlayer(String playerName) + { + for(OfflinePlayer offlinePlayer : server.getWhitelistedPlayers()) + { + if(offlinePlayer.getName().equalsIgnoreCase(playerName)) + return true; + } + return false; + } + + public static boolean CheckForPlayerEasyWhitelist(String playerName) + { + // Check just in case + if(!usingEasyWhitelist) + return false; + + // Load changes + try + { + easyWhitelistPlayers.load(new File(easyWhitelist.getDataFolder(), "config.yml")); + } + catch (IOException | InvalidConfigurationException e) + { + e.printStackTrace(); + } + + for(String name : easyWhitelistPlayers.getStringList("whitelisted")) + { + if(name.equalsIgnoreCase(playerName)) + return true; + } + return false; + } +} diff --git a/src/main/java/uk/co/angrybee/joe/VersionInfo.java b/src/main/java/uk/co/angrybee/joe/VersionInfo.java index 4fdc037..0e2e3f7 100644 --- a/src/main/java/uk/co/angrybee/joe/VersionInfo.java +++ b/src/main/java/uk/co/angrybee/joe/VersionInfo.java @@ -10,5 +10,5 @@ public class VersionInfo return "v." + getVersion(); } - private static String version = "1.3.8"; + private static String version = "1.4.0"; } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 422c6f3..142be1a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,8 +1,8 @@ name: DiscordWhitelister -version: 1.3.8 +version: 1.4.0 author: Joe Shimell main: uk.co.angrybee.joe.DiscordWhitelister -description: Discord whitelister bot. +description: Discord Whitelister. commands: discordwhitelister: description: See info about this plugin