From dc1e06ebcef4886568af1378ffeff406a5408428 Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 22 May 2016 01:57:10 +0100 Subject: [PATCH] Initial commit --- .gitignore | 37 ++ LICENSE.md | 21 ++ README.md | 28 ++ bukkit/pom.xml | 79 ++++ .../java/me/lucko/luckperms/BukkitConfig.java | 71 ++++ .../lucko/luckperms/CommandManagerBukkit.java | 30 ++ .../me/lucko/luckperms/LPBukkitPlugin.java | 109 ++++++ .../java/me/lucko/luckperms/VaultHook.java | 150 ++++++++ .../luckperms/listeners/PlayerListener.java | 75 ++++ .../lucko/luckperms/runnables/UpdateTask.java | 25 ++ .../me/lucko/luckperms/users/BukkitUser.java | 52 +++ .../luckperms/users/BukkitUserManager.java | 53 +++ bukkit/src/main/resources/config.yml | 19 + bukkit/src/main/resources/plugin.yml | 10 + bungee/pom.xml | 74 ++++ .../java/me/lucko/luckperms/BungeeConfig.java | 78 ++++ .../me/lucko/luckperms/LPBungeePlugin.java | 112 ++++++ .../java/me/lucko/luckperms/MainCommand.java | 34 ++ .../luckperms/listeners/PlayerListener.java | 44 +++ .../lucko/luckperms/runnables/UpdateTask.java | 23 ++ .../me/lucko/luckperms/users/BungeeUser.java | 42 +++ .../luckperms/users/BungeeUserManager.java | 44 +++ bungee/src/main/resources/config.yml | 19 + bungee/src/main/resources/plugin.yml | 3 + common/pom.xml | 26 ++ .../me/lucko/luckperms/LuckPermsPlugin.java | 77 ++++ .../luckperms/commands/CommandManager.java | 113 ++++++ .../lucko/luckperms/commands/MainCommand.java | 42 +++ .../me/lucko/luckperms/commands/Sender.java | 8 + .../lucko/luckperms/commands/SubCommand.java | 35 ++ .../me/lucko/luckperms/commands/Util.java | 81 +++++ .../commands/group/CreateGroupCommand.java | 51 +++ .../commands/group/DeleteGroupCommand.java | 63 ++++ .../commands/group/GroupMainCommand.java | 103 ++++++ .../commands/group/GroupSubCommand.java | 29 ++ .../commands/group/ListGroupsCommand.java | 37 ++ .../group/subcommands/GroupClearCommand.java | 29 ++ .../subcommands/GroupHasPermCommand.java | 30 ++ .../group/subcommands/GroupInfoCommand.java | 31 ++ .../subcommands/GroupListNodesCommand.java | 27 ++ .../subcommands/GroupSetInheritCommand.java | 50 +++ .../GroupSetPermissionCommand.java | 60 ++++ .../GroupUnSetPermissionCommand.java | 52 +++ .../subcommands/GroupUnsetInheritCommand.java | 42 +++ .../luckperms/commands/misc/DebugCommand.java | 34 ++ .../luckperms/commands/misc/InfoCommand.java | 33 ++ .../luckperms/commands/misc/SyncCommand.java | 32 ++ .../commands/user/UserMainCommand.java | 115 ++++++ .../commands/user/UserSubCommand.java | 29 ++ .../user/subcommands/UserAddGroupCommand.java | 49 +++ .../user/subcommands/UserClearCommand.java | 30 ++ .../user/subcommands/UserGetUUIDCommand.java | 25 ++ .../user/subcommands/UserHasPermCommand.java | 30 ++ .../user/subcommands/UserInfoCommand.java | 34 ++ .../subcommands/UserListNodesCommand.java | 27 ++ .../subcommands/UserRemoveGroupCommand.java | 49 +++ .../subcommands/UserSetPermissionCommand.java | 60 ++++ .../UserUnSetPermissionCommand.java | 51 +++ .../me/lucko/luckperms/data/Datastore.java | 117 ++++++ .../data/DatastoreConfiguration.java | 15 + .../lucko/luckperms/data/HikariDatastore.java | 338 ++++++++++++++++++ .../exceptions/ObjectAlreadyHasException.java | 4 + .../ObjectLacksPermissionException.java | 4 + .../java/me/lucko/luckperms/groups/Group.java | 31 ++ .../lucko/luckperms/groups/GroupManager.java | 93 +++++ .../java/me/lucko/luckperms/users/User.java | 197 ++++++++++ .../me/lucko/luckperms/users/UserManager.java | 120 +++++++ .../luckperms/utils/LPConfiguration.java | 13 + .../luckperms/utils/PermissionObject.java | 234 ++++++++++++ pom.xml | 62 ++++ 70 files changed, 4044 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 bukkit/pom.xml create mode 100644 bukkit/src/main/java/me/lucko/luckperms/BukkitConfig.java create mode 100644 bukkit/src/main/java/me/lucko/luckperms/CommandManagerBukkit.java create mode 100644 bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java create mode 100644 bukkit/src/main/java/me/lucko/luckperms/VaultHook.java create mode 100644 bukkit/src/main/java/me/lucko/luckperms/listeners/PlayerListener.java create mode 100644 bukkit/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java create mode 100644 bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java create mode 100644 bukkit/src/main/java/me/lucko/luckperms/users/BukkitUserManager.java create mode 100644 bukkit/src/main/resources/config.yml create mode 100644 bukkit/src/main/resources/plugin.yml create mode 100644 bungee/pom.xml create mode 100644 bungee/src/main/java/me/lucko/luckperms/BungeeConfig.java create mode 100644 bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java create mode 100644 bungee/src/main/java/me/lucko/luckperms/MainCommand.java create mode 100644 bungee/src/main/java/me/lucko/luckperms/listeners/PlayerListener.java create mode 100644 bungee/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java create mode 100644 bungee/src/main/java/me/lucko/luckperms/users/BungeeUser.java create mode 100644 bungee/src/main/java/me/lucko/luckperms/users/BungeeUserManager.java create mode 100644 bungee/src/main/resources/config.yml create mode 100644 bungee/src/main/resources/plugin.yml create mode 100644 common/pom.xml create mode 100644 common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/CommandManager.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/MainCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/Sender.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/SubCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/Util.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/CreateGroupCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/DeleteGroupCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/GroupMainCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/GroupSubCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/ListGroupsCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupClearCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupHasPermCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupInfoCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupListNodesCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupSetInheritCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupSetPermissionCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupUnSetPermissionCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupUnsetInheritCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/misc/DebugCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/misc/InfoCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/misc/SyncCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/UserMainCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/UserSubCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserAddGroupCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserClearCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserGetUUIDCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserHasPermCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserInfoCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserListNodesCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserRemoveGroupCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserSetPermissionCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserUnSetPermissionCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/data/Datastore.java create mode 100644 common/src/main/java/me/lucko/luckperms/data/DatastoreConfiguration.java create mode 100644 common/src/main/java/me/lucko/luckperms/data/HikariDatastore.java create mode 100644 common/src/main/java/me/lucko/luckperms/exceptions/ObjectAlreadyHasException.java create mode 100644 common/src/main/java/me/lucko/luckperms/exceptions/ObjectLacksPermissionException.java create mode 100644 common/src/main/java/me/lucko/luckperms/groups/Group.java create mode 100644 common/src/main/java/me/lucko/luckperms/groups/GroupManager.java create mode 100644 common/src/main/java/me/lucko/luckperms/users/User.java create mode 100644 common/src/main/java/me/lucko/luckperms/users/UserManager.java create mode 100644 common/src/main/java/me/lucko/luckperms/utils/LPConfiguration.java create mode 100644 common/src/main/java/me/lucko/luckperms/utils/PermissionObject.java create mode 100644 pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9684a8ba --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# built application files +*.jar + +# Java class files +*.class + +# Local configuration file (sdk path, etc) +logs/ + +# Eclipse project files +.classpath +.project + +# Intellij project files +*.iml +*.ipr +*.iws +.idea/ + +# Gradle +.gradletasknamecache +.gradle/ +build/ +bin/ +gradle/ +gradlew* + +# Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..54f7ac0f --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Luck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..631ad452 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# LuckPerms +A quite possibly shit™ permissions implementation for Bukkit/BungeeCord. + +### Why? +Yeah, I don't know. There are other more advanced, optimized, better programmed and thoroughly tested alternative plugins around, you should probably use those instead. I just wanted some specific features, and something that was compatible with BungeeCord. + +### Features + - **Group inheritance** - users can be members of multiple groups, groups can inherit other groups + - **Multi-server support** - data is synced across all servers/platforms + - **Per-server permissions/groups** - define permissions that only apply on certain servers + - **Vault Support** - hooks into Vault to integrate with other plugins + - **Everything is configured using commands** - no editing yml files, yuck + - **Efficient** - maybe? Who knows, it might be. + - **BungeeCord compatible** - my main motive for making this was that all other Bungee/Bukkit compatible perms plugins are utter aids. (At least, I couldn't find any decent ones) + +### Caveats + - Only supports MySQL + - Not at all tested and could be super unreliable + - It's quite possibly shit™ + +So, not anything major, really ¯\ _(ツ)_ /¯ + +### Commands +Command usage is printed when you supply too little arguments. + +Bukkit: `/luckperms` `/perms` `/permissions` `/lp` `/perm` + +Bungee: `/luckpermsbungee` `/bperms` `/bpermissions` `/lpb` `/bperm` diff --git a/bukkit/pom.xml b/bukkit/pom.xml new file mode 100644 index 00000000..17d53176 --- /dev/null +++ b/bukkit/pom.xml @@ -0,0 +1,79 @@ + + + + luckperms + me.lucko + 1.0-SNAPSHOT + + 4.0.0 + + luckperms-bukkit + 1.0-SNAPSHOT + jar + LuckPerms + + + clean package + LuckPerms + ${basedir}/src/main/java + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + package + + shade + + + true + + + + + + + + + + + org.bukkit + bukkit + 1.8.8-R0.1-SNAPSHOT + provided + + + + net.milkbowl.vault + VaultAPI + 1.5 + provided + + + + me.lucko + luckperms-common + ${project.parent.version} + compile + + + \ No newline at end of file diff --git a/bukkit/src/main/java/me/lucko/luckperms/BukkitConfig.java b/bukkit/src/main/java/me/lucko/luckperms/BukkitConfig.java new file mode 100644 index 00000000..15596940 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/BukkitConfig.java @@ -0,0 +1,71 @@ +package me.lucko.luckperms; + +import me.lucko.luckperms.utils.LPConfiguration; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; + +public class BukkitConfig implements LPConfiguration { + private final LPBukkitPlugin plugin; + private YamlConfiguration configuration; + + public BukkitConfig(LPBukkitPlugin plugin) { + this.plugin = plugin; + create(); + } + + private void create() { + File configFile = new File(plugin.getDataFolder(), "config.yml"); + + if (!configFile.exists()) { + configFile.getParentFile().mkdirs(); + plugin.saveResource("config.yml", false); + } + + configuration = new YamlConfiguration(); + + try { + configuration.load(configFile); + + } catch (InvalidConfigurationException | IOException e) { + e.printStackTrace(); + } + } + + @Override + public String getServer() { + return configuration.getString("server"); + } + + @Override + public String getPrefix() { + return configuration.getString("prefix"); + } + + @Override + public int getSyncTime() { + return configuration.getInt("sql.sync-minutes"); + } + + @Override + public String getDefaultGroupNode() { + return "luckperms.group." + configuration.getString("default-group"); + } + + @Override + public String getDefaultGroupName() { + return configuration.getString("default-group"); + } + + @Override + public boolean getIncludeGlobalPerms() { + return configuration.getBoolean("include-global"); + } + + @Override + public String getDatabaseValue(String value) { + return configuration.getString("sql." + value); + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/CommandManagerBukkit.java b/bukkit/src/main/java/me/lucko/luckperms/CommandManagerBukkit.java new file mode 100644 index 00000000..26e56379 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/CommandManagerBukkit.java @@ -0,0 +1,30 @@ +package me.lucko.luckperms; + +import me.lucko.luckperms.commands.CommandManager; +import me.lucko.luckperms.commands.Sender; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; + +import java.util.Arrays; + +class CommandManagerBukkit extends CommandManager implements CommandExecutor { + CommandManagerBukkit(LuckPermsPlugin plugin) { + super(plugin); + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + return onCommand(new Sender() { + @Override + public void sendMessage(String s) { + sender.sendMessage(s); + } + + @Override + public boolean hasPermission(String node) { + return sender.hasPermission(node); + } + }, Arrays.asList(args)); + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java new file mode 100644 index 00000000..9833fb07 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java @@ -0,0 +1,109 @@ +package me.lucko.luckperms; + +import lombok.Getter; +import me.lucko.luckperms.data.Datastore; +import me.lucko.luckperms.data.DatastoreConfiguration; +import me.lucko.luckperms.data.HikariDatastore; +import me.lucko.luckperms.groups.GroupManager; +import me.lucko.luckperms.listeners.PlayerListener; +import me.lucko.luckperms.runnables.UpdateTask; +import me.lucko.luckperms.users.BukkitUserManager; +import me.lucko.luckperms.users.UserManager; +import me.lucko.luckperms.utils.LPConfiguration; +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +import org.bukkit.command.PluginCommand; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.ServicePriority; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.Arrays; +import java.util.UUID; + +@Getter +public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { + public static final String VERSION = "v1.0"; + + private LPConfiguration configuration; + private UserManager userManager; + private GroupManager groupManager; + private Datastore datastore; + + @Override + public void onEnable() { + configuration = new BukkitConfig(this); + + // register events + PluginManager pm = Bukkit.getPluginManager(); + pm.registerEvents(new PlayerListener(this), this); + + // register commands + CommandManagerBukkit commandManager = new CommandManagerBukkit(this); + PluginCommand main = getServer().getPluginCommand("luckperms"); + main.setExecutor(commandManager); + main.setAliases(Arrays.asList("perms", "lp", "permissions", "p", "perm")); + + datastore = new HikariDatastore(this); + datastore.init(new DatastoreConfiguration( + configuration.getDatabaseValue("address"), + configuration.getDatabaseValue("database"), + configuration.getDatabaseValue("username"), + configuration.getDatabaseValue("password") + )); + + userManager = new BukkitUserManager(this); + groupManager = new GroupManager(this); + + int mins = getConfiguration().getSyncTime(); + if (mins > 0) { + long ticks = mins * 60 * 20; + new UpdateTask(this).runTaskTimer(this, ticks, ticks); + } + + // Provide vault support + try { + if (getServer().getPluginManager().isPluginEnabled("Vault")) { + getServer().getServicesManager().register(Permission.class, new VaultHook(this), this, ServicePriority.High); + getLogger().info("Registered Vault permission hook."); + } else { + getLogger().info("Vault not found."); + } + } catch (Exception e) { + getLogger().warning("Error whilst hooking into Vault."); + e.printStackTrace(); + } + + } + + @Override + public void doAsync(Runnable r) { + Bukkit.getScheduler().runTaskAsynchronously(this, r); + } + + @Override + public void doSync(Runnable r) { + Bukkit.getScheduler().runTask(this, r); + } + + @Override + public String getVersion() { + return VERSION; + } + + @Override + public String getPlayerStatus(UUID uuid) { + if (getServer().getPlayer(uuid) != null) return "&aOnline"; + return "&cOffline"; + } + + @Override + public int getPlayerCount() { + return getServer().getOnlinePlayers().size(); + } + + @Override + public void runUpdateTask() { + new UpdateTask(this).runTask(this); + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/VaultHook.java b/bukkit/src/main/java/me/lucko/luckperms/VaultHook.java new file mode 100644 index 00000000..6cc6f73d --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/VaultHook.java @@ -0,0 +1,150 @@ +package me.lucko.luckperms; + +import lombok.AllArgsConstructor; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.exceptions.ObjectLacksPermissionException; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.users.User; +import net.milkbowl.vault.permission.Permission; + +@AllArgsConstructor +public class VaultHook extends Permission { + private final LPBukkitPlugin plugin; + + @Override + public String getName() { + return "LuckPerms"; + } + + @Override + public boolean isEnabled() { + return plugin.getDatastore().isAcceptingLogins(); + } + + @Override + public boolean hasSuperPermsCompat() { + // Idk??? + return true; + } + + @Override + public boolean playerHas(String world, String player, String permission) { + final User user = plugin.getUserManager().getUser(player); + return user != null && user.hasPermission(permission, true); + } + + @Override + public boolean playerAdd(String world, String player, String permission) { + final User user = plugin.getUserManager().getUser(player); + if (user == null) return false; + + try { + user.setPermission(permission, true); + } catch (ObjectAlreadyHasException ignored) {} + plugin.getUserManager().saveUser(user, plugin.getDatastore()); + return true; + } + + @Override + public boolean playerRemove(String world, String player, String permission) { + final User user = plugin.getUserManager().getUser(player); + if (user == null) return false; + + try { + user.unsetPermission(permission); + } catch (ObjectLacksPermissionException ignored) {} + plugin.getUserManager().saveUser(user, plugin.getDatastore()); + return true; + } + + @Override + public boolean groupHas(String world, String groupName, String permission) { + final Group group = plugin.getGroupManager().getGroup(groupName); + return group != null && group.hasPermission(permission, true); + } + + @Override + public boolean groupAdd(String world, String groupName, String permission) { + final Group group = plugin.getGroupManager().getGroup(groupName); + if (group == null) return false; + + try { + group.setPermission(permission, true); + } catch (ObjectAlreadyHasException ignored) {} + plugin.runUpdateTask(); + return true; + } + + @Override + public boolean groupRemove(String world, String groupName, String permission) { + final Group group = plugin.getGroupManager().getGroup(groupName); + if (group == null) return false; + + try { + group.unsetPermission(permission); + } catch (ObjectLacksPermissionException ignored) {} + plugin.runUpdateTask(); + return true; + } + + @Override + public boolean playerInGroup(String world, String player, String group) { + final User user = plugin.getUserManager().getUser(player); + if (user == null) return false; + + return user.getGroupNames().contains(group); + } + + @Override + public boolean playerAddGroup(String world, String player, String groupName) { + final User user = plugin.getUserManager().getUser(player); + if (user == null) return false; + + final Group group = plugin.getGroupManager().getGroup(groupName); + if (group == null) return false; + + try { + user.addGroup(group); + } catch (ObjectAlreadyHasException ignored) {} + plugin.getUserManager().saveUser(user, plugin.getDatastore()); + return true; + } + + @Override + public boolean playerRemoveGroup(String world, String player, String groupName) { + final User user = plugin.getUserManager().getUser(player); + if (user == null) return false; + + final Group group = plugin.getGroupManager().getGroup(groupName); + if (group == null) return false; + + try { + user.removeGroup(group); + } catch (ObjectLacksPermissionException ignored) {} + plugin.getUserManager().saveUser(user, plugin.getDatastore()); + return true; + } + + @Override + public String[] getPlayerGroups(String world, String player) { + final User user = plugin.getUserManager().getUser(player); + if (user == null) return new String[0]; + + return user.getGroupNames().toArray(new String[0]); + } + + @Override + public String getPrimaryGroup(String world, String player) { + throw new UnsupportedOperationException(); + } + + @Override + public String[] getGroups() { + return plugin.getGroupManager().getGroups().keySet().toArray(new String[0]); + } + + @Override + public boolean hasGroupSupport() { + return true; + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/listeners/PlayerListener.java b/bukkit/src/main/java/me/lucko/luckperms/listeners/PlayerListener.java new file mode 100644 index 00000000..2c653ec6 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/listeners/PlayerListener.java @@ -0,0 +1,75 @@ +package me.lucko.luckperms.listeners; + +import lombok.AllArgsConstructor; +import me.lucko.luckperms.LPBukkitPlugin; +import me.lucko.luckperms.users.BukkitUser; +import me.lucko.luckperms.users.User; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +@AllArgsConstructor +public class PlayerListener implements Listener { + private final LPBukkitPlugin plugin; + + @EventHandler + public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) { + if (!plugin.getDatastore().isAcceptingLogins()) { + e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, color(plugin.getConfiguration().getPrefix() + + "&cError whilst validating login with the network. \nPlease contact an administrator.")); + return; + } + plugin.getDatastore().loadOrCreateUser(e.getUniqueId(), e.getName()); + } + + @EventHandler + public void onPlayerLogin(PlayerLoginEvent e) { + Player player = e.getPlayer(); + User user = plugin.getUserManager().getUser(player.getUniqueId()); + + if (user == null) { + e.disallow(PlayerLoginEvent.Result.KICK_OTHER, color(plugin.getConfiguration().getPrefix() + + "&cUser data could not be loaded. Please contact an administrator.")); + return; + } + + if (user instanceof BukkitUser) { + BukkitUser u = (BukkitUser) user; + u.setAttachment(player.addAttachment(plugin)); + } + + user.refreshPermissions(); + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent e) { + // Save UUID data for the player + plugin.getDatastore().saveUUIDData(e.getPlayer().getName(), e.getPlayer().getUniqueId(), success -> {}); + + User user = plugin.getUserManager().getUser(e.getPlayer().getUniqueId()); + if (user != null) { + // Refresh permissions again + user.refreshPermissions(); + } + + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent e) { + Player player = e.getPlayer(); + + // Unload the user from memory when they disconnect + User user = plugin.getUserManager().getUser(player.getUniqueId()); + plugin.getUserManager().unloadUser(user); + } + + public static String color(String string) { + return ChatColor.translateAlternateColorCodes('&', string); + } + +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java b/bukkit/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java new file mode 100644 index 00000000..f902593d --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java @@ -0,0 +1,25 @@ +package me.lucko.luckperms.runnables; + +import lombok.AllArgsConstructor; +import me.lucko.luckperms.LPBukkitPlugin; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +@AllArgsConstructor +public class UpdateTask extends BukkitRunnable { + private final LPBukkitPlugin plugin; + + @Override + public void run() { + plugin.getLogger().info("Running update task."); + + // Re-load all of the groups + plugin.getGroupManager().loadAllGroups(); + + // Refresh all online users. + for (Player p : Bukkit.getOnlinePlayers()) { + plugin.getDatastore().loadUser(p.getUniqueId(), success -> {}); + } + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java b/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java new file mode 100644 index 00000000..128d97c4 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java @@ -0,0 +1,52 @@ +package me.lucko.luckperms.users; + +import lombok.Getter; +import lombok.Setter; +import me.lucko.luckperms.LPBukkitPlugin; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.permissions.PermissionAttachment; + +import java.util.Map; +import java.util.UUID; + +public class BukkitUser extends User { + + private final LPBukkitPlugin plugin; + + @Getter + @Setter + private PermissionAttachment attachment = null; + + public BukkitUser(UUID uuid, LPBukkitPlugin plugin) { + super(uuid, plugin); + this.plugin = plugin; + } + + public BukkitUser(UUID uuid, String username, LPBukkitPlugin plugin) { + super(uuid, username, plugin); + this.plugin = plugin; + } + + @Override + public void refreshPermissions() { + Player player = Bukkit.getPlayer(getUuid()); + if (player == null) return; + + if (attachment == null) { + getPlugin().getLogger().warning("User " + getName() + " does not have a permissions attachment defined."); + setAttachment(player.addAttachment(plugin)); + } + + // Clear existing permissions + for (String p : attachment.getPermissions().keySet()) { + attachment.setPermission(p, false); + } + + // Re-add all defined permissions for the user + Map local = getLocalPermissions(getPlugin().getConfiguration().getServer(), null); + for (String node : local.keySet()) { + attachment.setPermission(node, local.get(node)); + } + } +} diff --git a/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUserManager.java b/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUserManager.java new file mode 100644 index 00000000..8a192830 --- /dev/null +++ b/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUserManager.java @@ -0,0 +1,53 @@ +package me.lucko.luckperms.users; + +import me.lucko.luckperms.LPBukkitPlugin; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.UUID; + +public class BukkitUserManager extends UserManager { + private final LPBukkitPlugin plugin; + + public BukkitUserManager(LPBukkitPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void unloadUser(User user) { + if (user != null) { + + if (user instanceof BukkitUser) { + BukkitUser u = (BukkitUser) user; + + if (u.getAttachment() != null) { + Player player = Bukkit.getPlayer(u.getUuid()); + + if (player != null) { + player.removeAttachment(u.getAttachment()); + } + u.setAttachment(null); + } + } + + getUsers().remove(user.getUuid()); + } + } + + @Override + public void cleanupUser(User user) { + if (Bukkit.getPlayer(user.getUuid()) == null) { + unloadUser(user); + } + } + + @Override + public User makeUser(UUID uuid) { + return new BukkitUser(uuid, plugin); + } + + @Override + public User makeUser(UUID uuid, String username) { + return new BukkitUser(uuid, username, plugin); + } +} diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml new file mode 100644 index 00000000..621e4e78 --- /dev/null +++ b/bukkit/src/main/resources/config.yml @@ -0,0 +1,19 @@ +# LuckPerms Configuration + +# The name of the server, used for server specific permissions. Set to 'global' to disable. +server: global + +# The default group assigned to all user on join. e.g. a value of "default" = luckperms.group.default +default-group: default + +# If users on this server should have their global permissions/groups applied. +include-global: true + +prefix: '&7&l[&b&lL&a&lP&7&l] &c' + +sql: + address: localhost:3306 + database: minecraft + username: root + password: '' + sync-minutes: 3 \ No newline at end of file diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml new file mode 100644 index 00000000..3258b2d5 --- /dev/null +++ b/bukkit/src/main/resources/plugin.yml @@ -0,0 +1,10 @@ +name: LuckPerms +author: Luck +version: 1.0 +main: me.lucko.luckperms.LPBukkitPlugin +softdepend: [Vault] +description: A permissions plugin +commands: + luckperms: + description: Manage permissions + aliases: [perms, permissions, lp, p, perm] \ No newline at end of file diff --git a/bungee/pom.xml b/bungee/pom.xml new file mode 100644 index 00000000..f10e14c8 --- /dev/null +++ b/bungee/pom.xml @@ -0,0 +1,74 @@ + + + + luckperms + me.lucko + 1.0-SNAPSHOT + + 4.0.0 + + luckperms-bungee + 1.0-SNAPSHOT + jar + LuckPerms + + + clean package + LuckPerms + ${basedir}/src/main/java + + + src/main/resources + true + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.3 + + + package + + shade + + + true + + + + + + + + + + + net.md-5 + bungeecord-api + 1.9-SNAPSHOT + jar + provided + + + + me.lucko + luckperms-common + ${project.parent.version} + compile + + + + \ No newline at end of file diff --git a/bungee/src/main/java/me/lucko/luckperms/BungeeConfig.java b/bungee/src/main/java/me/lucko/luckperms/BungeeConfig.java new file mode 100644 index 00000000..63f6c1a5 --- /dev/null +++ b/bungee/src/main/java/me/lucko/luckperms/BungeeConfig.java @@ -0,0 +1,78 @@ +package me.lucko.luckperms; + +import me.lucko.luckperms.utils.LPConfiguration; +import net.md_5.bungee.config.Configuration; +import net.md_5.bungee.config.ConfigurationProvider; +import net.md_5.bungee.config.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; + +public class BungeeConfig implements LPConfiguration { + private final LPBungeePlugin plugin; + private Configuration configuration; + + public BungeeConfig(LPBungeePlugin plugin) { + this.plugin = plugin; + reload(); + } + + private void reload() { + try { + configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(makeFile("config.yml")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private File makeFile(String file) throws IOException { + File cfg = new File(plugin.getDataFolder(), file); + + if (!cfg.exists()) { + plugin.getDataFolder().mkdir(); + try (InputStream is = plugin.getResourceAsStream(file)) { + Files.copy(is, cfg.toPath()); + } + } + + return cfg; + } + + + @Override + public String getServer() { + return configuration.getString("server"); + } + + @Override + public String getPrefix() { + return configuration.getString("prefix"); + } + + @Override + public int getSyncTime() { + return configuration.getInt("sql.sync-minutes"); + } + + @Override + public String getDefaultGroupNode() { + return "luckperms.group." + configuration.getString("default-group"); + } + + @Override + public String getDefaultGroupName() { + return configuration.getString("default-group"); + } + + @Override + public boolean getIncludeGlobalPerms() { + return configuration.getBoolean("include-global"); + } + + @Override + public String getDatabaseValue(String value) { + return configuration.getString("sql." + value); + } +} diff --git a/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java new file mode 100644 index 00000000..7fd2ad85 --- /dev/null +++ b/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java @@ -0,0 +1,112 @@ +package me.lucko.luckperms; + +import lombok.Getter; +import me.lucko.luckperms.commands.CommandManager; +import me.lucko.luckperms.data.Datastore; +import me.lucko.luckperms.data.DatastoreConfiguration; +import me.lucko.luckperms.data.HikariDatastore; +import me.lucko.luckperms.groups.GroupManager; +import me.lucko.luckperms.listeners.PlayerListener; +import me.lucko.luckperms.runnables.UpdateTask; +import me.lucko.luckperms.users.BungeeUserManager; +import me.lucko.luckperms.users.UserManager; +import me.lucko.luckperms.utils.LPConfiguration; +import net.md_5.bungee.api.plugin.Plugin; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { + public static final String VERSION = "v1.0"; + + @Getter + LPConfiguration configuration; + + @Getter + UserManager userManager; + + @Getter + GroupManager groupManager; + + @Getter + Datastore datastore; + + @Override + public void onEnable() { + configuration = new BungeeConfig(this); + + // register events + getProxy().getPluginManager().registerListener(this, new PlayerListener(this)); + + // register commands + getProxy().getPluginManager().registerCommand(this, new MainCommand(new CommandManager(this))); + + datastore = new HikariDatastore(this); + datastore.init(new DatastoreConfiguration( + configuration.getDatabaseValue("address"), + configuration.getDatabaseValue("database"), + configuration.getDatabaseValue("username"), + configuration.getDatabaseValue("password") + )); + + userManager = new BungeeUserManager(this); + groupManager = new GroupManager(this); + + int mins = getConfiguration().getSyncTime(); + if (mins > 0) { + getProxy().getScheduler().schedule(this, new UpdateTask(this), mins, mins, TimeUnit.MINUTES); + } + } + + + @Override + public UserManager getUserManager() { + return userManager; + } + + @Override + public GroupManager getGroupManager() { + return groupManager; + } + + @Override + public String getVersion() { + return VERSION; + } + + @Override + public String getPlayerStatus(UUID uuid) { + if (getProxy().getPlayer(uuid) != null) return "&aOnline"; + return "&cOffline"; + } + + @Override + public int getPlayerCount() { + return getProxy().getOnlineCount(); + } + + @Override + public LPConfiguration getConfiguration() { + return configuration; + } + + @Override + public Datastore getDatastore() { + return datastore; + } + + @Override + public void runUpdateTask() { + new UpdateTask(this).run(); + } + + @Override + public void doAsync(Runnable r) { + getProxy().getScheduler().runAsync(this, r); + } + + @Override + public void doSync(Runnable r) { + r.run(); + } +} diff --git a/bungee/src/main/java/me/lucko/luckperms/MainCommand.java b/bungee/src/main/java/me/lucko/luckperms/MainCommand.java new file mode 100644 index 00000000..d3605250 --- /dev/null +++ b/bungee/src/main/java/me/lucko/luckperms/MainCommand.java @@ -0,0 +1,34 @@ +package me.lucko.luckperms; + +import me.lucko.luckperms.commands.CommandManager; +import me.lucko.luckperms.commands.Sender; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.plugin.Command; + +import java.util.Arrays; + +public class MainCommand extends Command { + private final CommandManager manager; + + public MainCommand(CommandManager manager) { + super("luckpermsbungee", "luckperms.use", "bperms", "lpb", "bpermissions", "bp", "bperm"); + this.manager = manager; + + } + + @Override + public void execute(CommandSender sender, String[] args) { + manager.onCommand(new Sender() { + @Override + public void sendMessage(String s) { + sender.sendMessage(new TextComponent(s)); + } + + @Override + public boolean hasPermission(String node) { + return sender.hasPermission(node); + } + }, Arrays.asList(args)); + } +} diff --git a/bungee/src/main/java/me/lucko/luckperms/listeners/PlayerListener.java b/bungee/src/main/java/me/lucko/luckperms/listeners/PlayerListener.java new file mode 100644 index 00000000..adf5c428 --- /dev/null +++ b/bungee/src/main/java/me/lucko/luckperms/listeners/PlayerListener.java @@ -0,0 +1,44 @@ +package me.lucko.luckperms.listeners; + +import lombok.AllArgsConstructor; +import me.lucko.luckperms.LPBungeePlugin; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.data.Datastore; +import me.lucko.luckperms.users.User; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.event.PlayerDisconnectEvent; +import net.md_5.bungee.api.event.PostLoginEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; + +@AllArgsConstructor +public class PlayerListener implements Listener { + + private final LPBungeePlugin plugin; + + @EventHandler + public void onPlayerPostLogin(PostLoginEvent e) { + final ProxiedPlayer player = e.getPlayer(); + + plugin.getDatastore().loadOrCreateUser(player.getUniqueId(), player.getName(), success -> { + if (!success) { + e.getPlayer().sendMessage(new TextComponent(Util.color("&e&l[LP] &cPermissions data could not be loaded. Please contact an administrator."))); + } else { + User user = plugin.getUserManager().getUser(player.getUniqueId()); + user.refreshPermissions(); + } + }); + + plugin.getDatastore().saveUUIDData(e.getPlayer().getName(), e.getPlayer().getUniqueId(), success -> {}); + } + + @EventHandler + public void onPlayerQuit(PlayerDisconnectEvent e) { + ProxiedPlayer player = e.getPlayer(); + + // Unload the user from memory when they disconnect + User user = plugin.getUserManager().getUser(player.getUniqueId()); + plugin.getUserManager().unloadUser(user); + } +} diff --git a/bungee/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java b/bungee/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java new file mode 100644 index 00000000..2ee76172 --- /dev/null +++ b/bungee/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java @@ -0,0 +1,23 @@ +package me.lucko.luckperms.runnables; + +import lombok.AllArgsConstructor; +import me.lucko.luckperms.LPBungeePlugin; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +@AllArgsConstructor +public class UpdateTask implements Runnable { + private final LPBungeePlugin plugin; + + @Override + public void run() { + plugin.getLogger().info("Running update task."); + + // Re-load all of the groups + plugin.getGroupManager().loadAllGroups(); + + // Refresh all online users. + for (ProxiedPlayer p : plugin.getProxy().getPlayers()) { + plugin.getDatastore().loadUser(p.getUniqueId(), success -> {}); + } + } +} diff --git a/bungee/src/main/java/me/lucko/luckperms/users/BungeeUser.java b/bungee/src/main/java/me/lucko/luckperms/users/BungeeUser.java new file mode 100644 index 00000000..64b91cf9 --- /dev/null +++ b/bungee/src/main/java/me/lucko/luckperms/users/BungeeUser.java @@ -0,0 +1,42 @@ +package me.lucko.luckperms.users; + +import me.lucko.luckperms.LPBungeePlugin; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.UUID; + +public class BungeeUser extends User { + + private final LPBungeePlugin plugin; + + public BungeeUser(UUID uuid, LPBungeePlugin plugin) { + super(uuid, plugin); + this.plugin = plugin; + } + + public BungeeUser(UUID uuid, String username, LPBungeePlugin plugin) { + super(uuid, username, plugin); + this.plugin = plugin; + } + + @Override + public void refreshPermissions() { + ProxiedPlayer player = plugin.getProxy().getPlayer(getUuid()); + if (player == null) return; + + // Clear existing permissions + Collection perms = new ArrayList<>(player.getPermissions()); + for (String p : perms) { + player.setPermission(p, false); + } + + // Re-add all defined permissions for the user + Map local = getLocalPermissions(getPlugin().getConfiguration().getServer(), null); + for (String node : local.keySet()) { + player.setPermission(node, local.get(node)); + } + } +} diff --git a/bungee/src/main/java/me/lucko/luckperms/users/BungeeUserManager.java b/bungee/src/main/java/me/lucko/luckperms/users/BungeeUserManager.java new file mode 100644 index 00000000..fda70fd9 --- /dev/null +++ b/bungee/src/main/java/me/lucko/luckperms/users/BungeeUserManager.java @@ -0,0 +1,44 @@ +package me.lucko.luckperms.users; + +import me.lucko.luckperms.LPBungeePlugin; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +import java.util.UUID; + +public class BungeeUserManager extends UserManager { + private final LPBungeePlugin plugin; + + public BungeeUserManager(LPBungeePlugin plugin) { + this.plugin = plugin; + } + + @Override + public void unloadUser(User user) { + if (user != null) { + + ProxiedPlayer player = plugin.getProxy().getPlayer(user.getUuid()); + if (player != null) { + player.getPermissions().clear(); + } + + getUsers().remove(user.getUuid()); + } + } + + @Override + public void cleanupUser(User user) { + if (plugin.getProxy().getPlayer(user.getUuid()) == null) { + unloadUser(user); + } + } + + @Override + public User makeUser(UUID uuid) { + return new BungeeUser(uuid, plugin); + } + + @Override + public User makeUser(UUID uuid, String username) { + return new BungeeUser(uuid, username, plugin); + } +} diff --git a/bungee/src/main/resources/config.yml b/bungee/src/main/resources/config.yml new file mode 100644 index 00000000..bc0515ca --- /dev/null +++ b/bungee/src/main/resources/config.yml @@ -0,0 +1,19 @@ +# LuckPerms Configuration + +# The name of the server, used for server specific permissions. Set to 'global' to disable. +server: bungee + +# The default group assigned to all user on join. e.g. a value of "default" = luckperms.group.default +default-group: default + +# If users on this server should have their global permissions/groups applied. +include-global: false + +prefix: '&7&l[&b&lL&a&lP&7&l] &c' + +sql: + address: localhost:3306 + database: minecraft + username: root + password: '' + sync-minutes: 3 \ No newline at end of file diff --git a/bungee/src/main/resources/plugin.yml b/bungee/src/main/resources/plugin.yml new file mode 100644 index 00000000..9215088e --- /dev/null +++ b/bungee/src/main/resources/plugin.yml @@ -0,0 +1,3 @@ +name: LuckPerms +main: me.lucko.luckperms.LPBungeePlugin +author: Luck \ No newline at end of file diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 00000000..ef859dcb --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,26 @@ + + + + luckperms + me.lucko + 1.0-SNAPSHOT + + 4.0.0 + + luckperms-common + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.8 + 1.8 + + + + + \ No newline at end of file diff --git a/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java new file mode 100644 index 00000000..87c96003 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java @@ -0,0 +1,77 @@ +package me.lucko.luckperms; + +import me.lucko.luckperms.data.Datastore; +import me.lucko.luckperms.groups.GroupManager; +import me.lucko.luckperms.users.UserManager; +import me.lucko.luckperms.utils.LPConfiguration; + +import java.util.UUID; +import java.util.logging.Logger; + +public interface LuckPermsPlugin { + + /** + * Retrieves the {@link UserManager} used to manage users and their permissions/groups + * @return the {@link UserManager} object + */ + UserManager getUserManager(); + + /** + * Retrieves the {@link GroupManager} used to manage the loaded groups and modify their permissions + * @return the {@link GroupManager} object + */ + GroupManager getGroupManager(); + + /** + * Retrieves the {@link LPConfiguration} for getting values from the config + * @return the {@link LPConfiguration} implementation for the platform + */ + LPConfiguration getConfiguration(); + + /** + * Retrieves the {@link Datastore} for loading/saving plugin data + * @return the {@link Datastore} object + */ + Datastore getDatastore(); + + /** + * Retrieves the {@link Logger} for the plugin + * @return the plugin's {@link Logger} + */ + Logger getLogger(); + + /** + * @return the version of the plugin + */ + String getVersion(); + + /** + * Returns a colored string indicating the status of a player + * @param uuid The player's uuid + * @return a formatted status string + */ + String getPlayerStatus(UUID uuid); + + /** + * Gets the number of users online on the platform + * @return the number of users + */ + int getPlayerCount(); + + /** + * Runs an update task + */ + void runUpdateTask(); + + /** + * Execute a runnable asynchronously + * @param r the task to run + */ + void doAsync(Runnable r); + + /** + * Execute a runnable synchronously + * @param r the task to run + */ + void doSync(Runnable r); +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/CommandManager.java b/common/src/main/java/me/lucko/luckperms/commands/CommandManager.java new file mode 100644 index 00000000..9d911e36 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/CommandManager.java @@ -0,0 +1,113 @@ +package me.lucko.luckperms.commands; + +import lombok.Getter; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.group.CreateGroupCommand; +import me.lucko.luckperms.commands.group.DeleteGroupCommand; +import me.lucko.luckperms.commands.group.GroupMainCommand; +import me.lucko.luckperms.commands.group.ListGroupsCommand; +import me.lucko.luckperms.commands.group.subcommands.*; +import me.lucko.luckperms.commands.misc.DebugCommand; +import me.lucko.luckperms.commands.misc.InfoCommand; +import me.lucko.luckperms.commands.misc.SyncCommand; +import me.lucko.luckperms.commands.user.UserMainCommand; +import me.lucko.luckperms.commands.user.subcommands.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +public class CommandManager { + private final LuckPermsPlugin plugin; + + @Getter + private final List mainCommands = new ArrayList<>(); + + public CommandManager(LuckPermsPlugin plugin) { + this.plugin = plugin; + + UserMainCommand userCommand = new UserMainCommand(); + this.registerMainCommand(userCommand); + userCommand.registerSubCommand(new UserAddGroupCommand()); + userCommand.registerSubCommand(new UserClearCommand()); + userCommand.registerSubCommand(new UserGetUUIDCommand()); + userCommand.registerSubCommand(new UserHasPermCommand()); + userCommand.registerSubCommand(new UserInfoCommand()); + userCommand.registerSubCommand(new UserListNodesCommand()); + userCommand.registerSubCommand(new UserRemoveGroupCommand()); + userCommand.registerSubCommand(new UserSetPermissionCommand()); + userCommand.registerSubCommand(new UserUnSetPermissionCommand()); + + GroupMainCommand groupCommand = new GroupMainCommand(); + this.registerMainCommand(groupCommand); + groupCommand.registerSubCommand(new GroupClearCommand()); + groupCommand.registerSubCommand(new GroupHasPermCommand()); + groupCommand.registerSubCommand(new GroupInfoCommand()); + groupCommand.registerSubCommand(new GroupListNodesCommand()); + groupCommand.registerSubCommand(new GroupSetInheritCommand()); + groupCommand.registerSubCommand(new GroupSetPermissionCommand()); + groupCommand.registerSubCommand(new GroupUnsetInheritCommand()); + groupCommand.registerSubCommand(new GroupUnSetPermissionCommand()); + + this.registerMainCommand(new CreateGroupCommand()); + this.registerMainCommand(new DeleteGroupCommand()); + this.registerMainCommand(new ListGroupsCommand()); + this.registerMainCommand(new DebugCommand()); + this.registerMainCommand(new InfoCommand()); + this.registerMainCommand(new SyncCommand()); + } + + /** + * Generic on command method to be called from the command executor object of the platform + * @param sender who sent the command + * @param args the arguments provided + * @return if the command was successful (hint: it always is :> ) + */ + public boolean onCommand(Sender sender, List args) { + if (args.size() == 0) { + Util.sendPluginMessage(sender, "&6Running &bLuckPerms " + plugin.getVersion() + "&6."); + + if (sender.hasPermission("luckperms.info")) { + for (MainCommand c : mainCommands) { + Util.sendPluginMessage(sender, "&e-> &d" + c.getUsage()); + } + } + + } else { + String c = args.get(0); + MainCommand main = null; + + for (MainCommand mainCommand : mainCommands) { + if (mainCommand.getName().equalsIgnoreCase(c)) { + main = mainCommand; + break; + } + } + + if (main == null) { + Util.sendPluginMessage(sender, "Command not recognised."); + return true; + } + + if (main.getRequiredArgsLength() == 0) { + main.execute(plugin, sender, null); + return true; + } + + if (args.size() == 1) { + main.sendUsage(sender); + return true; + } + + main.execute(plugin, sender, new ArrayList<>(args.subList(1, args.size()))); + } + return true; + + } + + public void registerMainCommand(MainCommand command) { + plugin.getLogger().log(Level.INFO, "[CommandManager] Registered main command '" + command.getName() + "'"); + mainCommands.add(command); + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/MainCommand.java b/common/src/main/java/me/lucko/luckperms/commands/MainCommand.java new file mode 100644 index 00000000..1ca2b310 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/MainCommand.java @@ -0,0 +1,42 @@ +package me.lucko.luckperms.commands; + +import lombok.Getter; +import me.lucko.luckperms.LuckPermsPlugin; + +import java.util.List; +import java.util.stream.Collectors; + +public abstract class MainCommand { + + @Getter + private final String name; + + @Getter + private final String usage; + + @Getter + private final int requiredArgsLength; + + public MainCommand(String name, String usage, int requiredArgsLength) { + this.name = name; + this.usage = usage; + this.requiredArgsLength = requiredArgsLength; + } + + protected abstract void execute(LuckPermsPlugin plugin, Sender sender, List args); + public abstract List getSubCommands(); + + protected void sendUsage(Sender sender) { + List subs = getSubCommands().stream().filter(s -> s.isAuthorized(sender)).collect(Collectors.toList()); + if (subs.size() > 0) { + Util.sendPluginMessage(sender, "&e" + getName() + " Sub Commands:"); + + for (SubCommand s : subs) { + s.sendUsage(sender); + } + + } else { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/Sender.java b/common/src/main/java/me/lucko/luckperms/commands/Sender.java new file mode 100644 index 00000000..890b4b3d --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/Sender.java @@ -0,0 +1,8 @@ +package me.lucko.luckperms.commands; + +public interface Sender { + + void sendMessage(String s); + boolean hasPermission(String node); + +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/SubCommand.java b/common/src/main/java/me/lucko/luckperms/commands/SubCommand.java new file mode 100644 index 00000000..376e6f39 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/SubCommand.java @@ -0,0 +1,35 @@ +package me.lucko.luckperms.commands; + +import lombok.Getter; + +public abstract class SubCommand { + + @Getter + private final String name; + + @Getter + private final String description; + + @Getter + private final String usage; + + @Getter + private final String permission; + + public SubCommand(String name, String description, String usage, String permission) { + this.name = name; + this.description = description; + this.usage = usage; + this.permission = permission; + } + + public boolean isAuthorized(Sender sender) { + return sender.hasPermission(permission); + } + + public void sendUsage(Sender sender) { + Util.sendPluginMessage(sender, "&e-> &d" + getUsage()); + } + + public abstract boolean isArgLengthInvalid(int argLength); +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/Util.java b/common/src/main/java/me/lucko/luckperms/commands/Util.java new file mode 100644 index 00000000..b532172e --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/Util.java @@ -0,0 +1,81 @@ +package me.lucko.luckperms.commands; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class Util { + + public static void sendPluginMessage(Sender sender, String message) { + // TODO: Pull the prefix from the config somehow + sender.sendMessage(color("&7&l[&b&lL&a&lP&7&l] &c" + message)); + } + + public static String color(String s) { + return translateAlternateColorCodes('&', s); + } + + public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) { + // Stolen from Bukkit :> + char[] b = textToTranslate.toCharArray(); + + for(int i = 0; i < b.length - 1; ++i) { + if(b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i + 1]) > -1) { + b[i] = 167; + b[i + 1] = Character.toLowerCase(b[i + 1]); + } + } + + return new String(b); + } + + public static void sendBoolean(Sender sender, String node, boolean b) { + if (b) { + sender.sendMessage(Util.color("&b" + node + ": &atrue")); + } else { + sender.sendMessage(Util.color("&b" + node + ": &cfalse")); + } + } + + public static String listToCommaSep(List strings) { + if (strings.isEmpty()) return "&6None"; + + StringBuilder sb = new StringBuilder(); + + for (String s : strings) { + sb.append("&6").append(s).append("&7, "); + } + + return sb.delete(sb.length() - 2, sb.length()).toString(); + } + + public static String nodesToString(Map nodes) { + if (nodes.isEmpty()) return "&6None"; + + StringBuilder sb = new StringBuilder(); + + for (String node : nodes.keySet()) { + if (nodes.get(node)) { + sb.append("&a").append(node).append("&7, "); + } else { + sb.append("&c").append(node).append("&7, "); + } + } + + return sb.delete(sb.length() - 2, sb.length()).toString(); + } + + public static UUID parseUuid(String s) { + try { + return UUID.fromString(s); + } catch (IllegalArgumentException e) { + try { + return UUID.fromString(s.replaceAll( + "(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", + "$1-$2-$3-$4-$5")); + } catch (IllegalArgumentException e1) { + return null; + } + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/CreateGroupCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/CreateGroupCommand.java new file mode 100644 index 00000000..08151ce9 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/CreateGroupCommand.java @@ -0,0 +1,51 @@ +package me.lucko.luckperms.commands.group; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; + +import java.util.ArrayList; +import java.util.List; + +public class CreateGroupCommand extends MainCommand { + public CreateGroupCommand() { + super("CreateGroup", "/perms creategroup ", 1); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, List args) { + if (!sender.hasPermission("luckperms.creategroup")) { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + return; + } + + if (args.size() == 0) { + sendUsage(sender); + return; + } + + String groupName = args.get(0).toLowerCase(); + + plugin.getDatastore().loadGroup(groupName, success -> { + if (success) { + Util.sendPluginMessage(sender, "That group already exists!"); + } else { + plugin.getDatastore().createAndLoadGroup(groupName, success1 -> { + if (!success1) { + Util.sendPluginMessage(sender, "There was an error whilst creating the group."); + } else { + Util.sendPluginMessage(sender, "&b" + groupName + "&a was successfully created."); + plugin.runUpdateTask(); + } + }); + } + }); + } + + @Override + public List getSubCommands() { + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/DeleteGroupCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/DeleteGroupCommand.java new file mode 100644 index 00000000..a9873af1 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/DeleteGroupCommand.java @@ -0,0 +1,63 @@ +package me.lucko.luckperms.commands.group; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.groups.Group; + +import java.util.ArrayList; +import java.util.List; + +public class DeleteGroupCommand extends MainCommand { + public DeleteGroupCommand() { + super("DeleteGroup", "/perms deletegroup ", 1); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, List args) { + if (!sender.hasPermission("luckperms.deletegroup")) { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + return; + } + + if (args.size() == 0) { + sendUsage(sender); + return; + } + + String groupName = args.get(0).toLowerCase(); + + if (groupName.equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) { + Util.sendPluginMessage(sender, "You cannot delete the default group."); + return; + } + + plugin.getDatastore().loadGroup(groupName, success -> { + if (!success) { + Util.sendPluginMessage(sender, "That group does not exist!"); + } else { + + Group group = plugin.getGroupManager().getGroup(groupName); + if (group == null) { + Util.sendPluginMessage(sender, "An unexpected error occurred."); + } else { + plugin.getDatastore().deleteGroup(group, success1 -> { + if (!success1) { + Util.sendPluginMessage(sender, "There was an error whilst creating the group."); + } else { + Util.sendPluginMessage(sender, "&b" + groupName + "&a was successfully deleted."); + plugin.runUpdateTask(); + } + }); + } + } + }); + } + + @Override + public List getSubCommands() { + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/GroupMainCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/GroupMainCommand.java new file mode 100644 index 00000000..0b146161 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/GroupMainCommand.java @@ -0,0 +1,103 @@ +package me.lucko.luckperms.commands.group; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.groups.Group; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class GroupMainCommand extends MainCommand { + + private final List subCommands = new ArrayList<>(); + + public GroupMainCommand() { + super("Group", "/perms group ", 2); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, List args) { + if (args.size() <= 1) { + sendUsage(sender); + return; + } + + List strippedArgs = new ArrayList<>(); + if (args.size() > 2) { + strippedArgs.addAll(args.subList(2, args.size())); + } + + String c = args.get(1); + GroupSubCommand tempSub = null; + + for (GroupSubCommand s : subCommands) { + if (s.getName().equalsIgnoreCase(c)) { + tempSub = s; + break; + } + } + + final GroupSubCommand sub = tempSub; + + if (sub == null) { + Util.sendPluginMessage(sender, "Command not recognised."); + return; + } + + + if (!sub.isAuthorized(sender)) { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + return; + } + + String g = args.get(0).toLowerCase(); + + plugin.getDatastore().loadGroup(g, success -> { + if (!success) { + Util.sendPluginMessage(sender, "&eGroup could not be found."); + return; + } + + Group group = plugin.getGroupManager().getGroup(g); + if (group == null) { + Util.sendPluginMessage(sender, "&eGroup could not be found."); + return; + } + + if (sub.isArgLengthInvalid(strippedArgs.size())) { + sub.sendUsage(sender); + return; + } + + sub.execute(plugin, sender, group, strippedArgs); + }); + } + + @Override + public List getSubCommands() { + return subCommands; + } + + public void registerSubCommand(GroupSubCommand subCommand) { + subCommands.add(subCommand); + } + + @Override + protected void sendUsage(Sender sender) { + List subs = getSubCommands().stream().filter(s -> s.isAuthorized(sender)).collect(Collectors.toList()); + if (subs.size() > 0) { + Util.sendPluginMessage(sender, "&e" + getName() + " Sub Commands:"); + + for (SubCommand s : subs) { + s.sendUsage(sender); + } + + } else { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/GroupSubCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/GroupSubCommand.java new file mode 100644 index 00000000..bf95f1ec --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/GroupSubCommand.java @@ -0,0 +1,29 @@ +package me.lucko.luckperms.commands.group; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public abstract class GroupSubCommand extends SubCommand { + public GroupSubCommand(String name, String description, String usage, String permission) { + super(name, description, usage, permission); + } + + protected abstract void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args); + + protected void saveGroup(Group group, Sender sender, LuckPermsPlugin plugin) { + plugin.getDatastore().saveGroup(group, success -> { + if (success) { + Util.sendPluginMessage(sender, "&7(Group data was saved to the datastore)"); + } else { + Util.sendPluginMessage(sender, "There was an error whilst saving the group."); + } + + plugin.runUpdateTask(); + }); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/ListGroupsCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/ListGroupsCommand.java new file mode 100644 index 00000000..1afbd2ab --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/ListGroupsCommand.java @@ -0,0 +1,37 @@ +package me.lucko.luckperms.commands.group; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; + +import java.util.ArrayList; +import java.util.List; + +public class ListGroupsCommand extends MainCommand { + public ListGroupsCommand() { + super("ListGroups", "/perms listgroups", 0); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, List args) { + if (!sender.hasPermission("luckperms.listgroups")) { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + return; + } + + plugin.getDatastore().loadAllGroups(success -> { + if (!success) { + Util.sendPluginMessage(sender, "Unable to load all groups."); + } else { + Util.sendPluginMessage(sender, "&aGroups: " + Util.listToCommaSep(new ArrayList<>(plugin.getGroupManager().getGroups().keySet()))); + } + }); + } + + @Override + public List getSubCommands() { + return null; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupClearCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupClearCommand.java new file mode 100644 index 00000000..1bb30b49 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupClearCommand.java @@ -0,0 +1,29 @@ +package me.lucko.luckperms.commands.group.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.group.GroupSubCommand; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public class GroupClearCommand extends GroupSubCommand { + public GroupClearCommand() { + super("clear", "Clears a groups permissions", + "/perms group clear", "luckperms.group.clear"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args) { + group.clearNodes(); + Util.sendPluginMessage(sender, "&b" + group.getName() + "&a's permissions were cleared."); + + saveGroup(group, sender, plugin); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return true; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupHasPermCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupHasPermCommand.java new file mode 100644 index 00000000..886bfd21 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupHasPermCommand.java @@ -0,0 +1,30 @@ +package me.lucko.luckperms.commands.group.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.group.GroupSubCommand; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public class GroupHasPermCommand extends GroupSubCommand { + public GroupHasPermCommand() { + super("haspermission", "Checks to see if a group has a certain permission node", + "/perms group haspermission [server]", "luckperms.group.haspermission"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args) { + if (args.size() >= 2) { + Util.sendBoolean(sender, args.get(0), group.hasPermission(args.get(0), true, args.get(1))); + } else { + Util.sendBoolean(sender, args.get(0), group.hasPermission(args.get(0), true, "global")); + } + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return argLength == 0; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupInfoCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupInfoCommand.java new file mode 100644 index 00000000..00f308a1 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupInfoCommand.java @@ -0,0 +1,31 @@ +package me.lucko.luckperms.commands.group.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.group.GroupSubCommand; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public class GroupInfoCommand extends GroupSubCommand { + public GroupInfoCommand() { + super("info", "Gives info about the group", + "/perms group info", "luckperms.group.info"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args) { + final String prefix = plugin.getConfiguration().getPrefix(); + String sb = prefix + "&d-> &eGroup: &6" + group.getName() + "\n" + + prefix + "&d-> &ePermissions: &6" + group.getNodes().keySet().size() + "\n" + + prefix + "&d-> &bUse &a/perms group " + group.getName() + " listnodes &bto see all permissions."; + + sender.sendMessage(Util.color(sb)); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return false; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupListNodesCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupListNodesCommand.java new file mode 100644 index 00000000..05519cc1 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupListNodesCommand.java @@ -0,0 +1,27 @@ +package me.lucko.luckperms.commands.group.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.group.GroupSubCommand; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public class GroupListNodesCommand extends GroupSubCommand { + public GroupListNodesCommand() { + super("listnodes", "Lists the permission nodes the group has", + "/perms group listnodes", "luckperms.group.listnodes"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args) { + Util.sendPluginMessage(sender, "&e" + group.getName() + "'s Nodes:"); + sender.sendMessage(Util.color(Util.nodesToString(group.getNodes()))); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return false; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupSetInheritCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupSetInheritCommand.java new file mode 100644 index 00000000..5b0098fc --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupSetInheritCommand.java @@ -0,0 +1,50 @@ +package me.lucko.luckperms.commands.group.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.group.GroupSubCommand; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public class GroupSetInheritCommand extends GroupSubCommand { + public GroupSetInheritCommand() { + super("setinherit", "Sets another group for this group to inherit permissions from", + "/perms group setinherit [server]", "luckperms.group.setinherit"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args) { + String groupName = args.get(0).toLowerCase(); + + plugin.getDatastore().loadGroup(groupName, success -> { + if (!success) { + Util.sendPluginMessage(sender, groupName + " does not exist!"); + } else { + final String node = "luckperms.group." + groupName; + + try { + if (args.size() == 2) { + final String server = args.get(1).toLowerCase(); + group.setPermission(node, true, server); + Util.sendPluginMessage(sender, "&b" + group.getName() + "&a now inherits permissions from &b" + groupName + "&a on server &b" + server + "&a."); + } else { + group.setPermission(node, true); + Util.sendPluginMessage(sender, "&b" + group.getName() + "&a now inherits permissions from &b" + groupName + "&a."); + } + + saveGroup(group, sender, plugin); + } catch (ObjectAlreadyHasException e) { + Util.sendPluginMessage(sender, group.getName() + " already inherits '" + groupName + "'."); + } + } + }); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return argLength == 0; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupSetPermissionCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupSetPermissionCommand.java new file mode 100644 index 00000000..41086fc1 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupSetPermissionCommand.java @@ -0,0 +1,60 @@ +package me.lucko.luckperms.commands.group.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.group.GroupSubCommand; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public class GroupSetPermissionCommand extends GroupSubCommand { + public GroupSetPermissionCommand() { + super("set", "Sets a permission for a group", + "/perms group set [server]", "luckperms.group.setpermission"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args) { + String node = args.get(0); + String bool = args.get(1); + + if (node.contains("/")) { + sendUsage(sender); + return; + } + + if (node.matches(".*luckperms\\.group\\..*")) { + Util.sendPluginMessage(sender, "Use the inherit command instead of specifying the node."); + return; + } + + if (!bool.equalsIgnoreCase("true") && !bool.equalsIgnoreCase("false")) { + sendUsage(sender); + return; + } + + boolean b = Boolean.parseBoolean(bool); + + try { + if (args.size() == 3) { + final String server = args.get(2).toLowerCase(); + group.setPermission(node, b, server); + Util.sendPluginMessage(sender, "&aSet &b" + node + "&a to &b" + bool + "&a for &b" + group.getName() + "&a on server &b" + server + "&a."); + } else { + group.setPermission(node, b); + Util.sendPluginMessage(sender, "&aSet &b" + node + "&a to " + bool + " for &b" + group.getName() + "&a."); + } + + saveGroup(group, sender, plugin); + } catch (ObjectAlreadyHasException e) { + Util.sendPluginMessage(sender, group.getName() + " already has this permission!"); + } + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return argLength < 2; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupUnSetPermissionCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupUnSetPermissionCommand.java new file mode 100644 index 00000000..25f46ccf --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupUnSetPermissionCommand.java @@ -0,0 +1,52 @@ +package me.lucko.luckperms.commands.group.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.group.GroupSubCommand; +import me.lucko.luckperms.exceptions.ObjectLacksPermissionException; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public class GroupUnSetPermissionCommand extends GroupSubCommand { + public GroupUnSetPermissionCommand() { + super("unset", "Unsets a permission for a group", + "/perms group unset [server]", "luckperms.group.unsetpermission"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args) { + String node = args.get(0); + + if (node.contains("/")) { + sendUsage(sender); + return; + } + + if (node.matches(".*luckperms\\.group\\..*")) { + Util.sendPluginMessage(sender, "Use the uninherit command instead of specifying the node."); + return; + } + + try { + if (args.size() == 2) { + final String server = args.get(1).toLowerCase(); + group.unsetPermission(node, server); + Util.sendPluginMessage(sender, "&aUnset &b" + node + "&a for &b" + group.getName() + "&a on server &b" + server + "&a."); + } else { + group.unsetPermission(node); + Util.sendPluginMessage(sender, "&aUnset &b" + node + "&a for &b" + group.getName() + "&a."); + } + + saveGroup(group, sender, plugin); + } catch (ObjectLacksPermissionException e) { + Util.sendPluginMessage(sender, "That group does not have this permission set."); + } + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return argLength == 0; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupUnsetInheritCommand.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupUnsetInheritCommand.java new file mode 100644 index 00000000..2b011748 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupUnsetInheritCommand.java @@ -0,0 +1,42 @@ +package me.lucko.luckperms.commands.group.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.group.GroupSubCommand; +import me.lucko.luckperms.exceptions.ObjectLacksPermissionException; +import me.lucko.luckperms.groups.Group; + +import java.util.List; + +public class GroupUnsetInheritCommand extends GroupSubCommand { + public GroupUnsetInheritCommand() { + super("unsetinherit", "Unsets another group for this group to inherit permissions from", + "/perms group unsetinherit [server]", "luckperms.group.unsetinherit"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, Group group, List args) { + String groupName = args.get(0).toLowerCase(); + + String server; + if (args.size() == 2) { + server = args.get(1).toLowerCase(); + } else { + server = "global"; + } + + try { + group.unsetPermission("luckperms.group." + groupName, server); + Util.sendPluginMessage(sender, "&b" + group.getName() + "&a no longer inherits permissions from &b" + groupName + "&a on server &b" + server + "&a."); + saveGroup(group, sender, plugin); + } catch (ObjectLacksPermissionException e) { + Util.sendPluginMessage(sender, "That group does not inherit '" + groupName + "'."); + } + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return argLength == 0; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/misc/DebugCommand.java b/common/src/main/java/me/lucko/luckperms/commands/misc/DebugCommand.java new file mode 100644 index 00000000..bb845b51 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/misc/DebugCommand.java @@ -0,0 +1,34 @@ +package me.lucko.luckperms.commands.misc; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; + +import java.util.ArrayList; +import java.util.List; + +public class DebugCommand extends MainCommand { + public DebugCommand() { + super("Debug", "/perms debug", 0); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, List args) { + if (!sender.hasPermission("luckperms.debug")) { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + return; + } + + Util.sendPluginMessage(sender, "&d>> Debug Info"); + Util.sendPluginMessage(sender, "&eOnline Players: &6" + plugin.getPlayerCount()); + Util.sendPluginMessage(sender, "&eLoaded Users: &6" + plugin.getUserManager().getUsers().size()); + Util.sendPluginMessage(sender, "&eLoaded Groups: &6" + plugin.getGroupManager().getGroups().size()); + } + + @Override + public List getSubCommands() { + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/misc/InfoCommand.java b/common/src/main/java/me/lucko/luckperms/commands/misc/InfoCommand.java new file mode 100644 index 00000000..1c4f812b --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/misc/InfoCommand.java @@ -0,0 +1,33 @@ +package me.lucko.luckperms.commands.misc; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; + +import java.util.ArrayList; +import java.util.List; + +public class InfoCommand extends MainCommand { + public InfoCommand() { + super("Info", "/perms info", 0); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, List args) { + if (!sender.hasPermission("luckperms.info")) { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + return; + } + + Util.sendPluginMessage(sender, "&6Running &bLuckPerms " + plugin.getVersion() + "&6."); + Util.sendPluginMessage(sender, "&eAuthor: &6Luck"); + Util.sendPluginMessage(sender, "&eStorage Method: &6" + plugin.getDatastore().getName()); + } + + @Override + public List getSubCommands() { + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/misc/SyncCommand.java b/common/src/main/java/me/lucko/luckperms/commands/misc/SyncCommand.java new file mode 100644 index 00000000..6f45d1e4 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/misc/SyncCommand.java @@ -0,0 +1,32 @@ +package me.lucko.luckperms.commands.misc; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; + +import java.util.ArrayList; +import java.util.List; + +public class SyncCommand extends MainCommand { + public SyncCommand() { + super("Sync", "/perms sync", 0); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, List args) { + if (!sender.hasPermission("luckperms.sync")) { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + return; + } + + Util.sendPluginMessage(sender, "&bRunning update task for all online users."); + plugin.runUpdateTask(); + } + + @Override + public List getSubCommands() { + return new ArrayList<>(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/UserMainCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/UserMainCommand.java new file mode 100644 index 00000000..8d7fccee --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/UserMainCommand.java @@ -0,0 +1,115 @@ +package me.lucko.luckperms.commands.user; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.users.User; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class UserMainCommand extends MainCommand{ + + private final List subCommands = new ArrayList<>(); + + public UserMainCommand() { + super("User", "/perms user ", 2); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, List args) { + if (args.size() <= 1) { + sendUsage(sender); + return; + } + + // The first argument is the name of the user, the second is the command + String command = args.get(1); + UserSubCommand tempSub = null; + + // Try to identify the command used + for (UserSubCommand s : subCommands) { + if (s.getName().equalsIgnoreCase(command)) { + tempSub = s; + break; + } + } + + // The command the sender used + final UserSubCommand sub = tempSub; + + if (sub == null) { + Util.sendPluginMessage(sender, "Command not recognised."); + return; + } + + if (!sub.isAuthorized(sender)) { + Util.sendPluginMessage(sender, "You do not have permission to use this command!"); + return; + } + + // The arguments to be passed onto the sub command + List strippedArgs = new ArrayList<>(); + if (args.size() > 2) { + strippedArgs.addAll(args.subList(2, args.size())); + } + + String user = args.get(0); + + UUID u = Util.parseUuid(user); + if (u != null) { + runSub(plugin, sender, u, sub, strippedArgs); + return; + } + + if (user.length() <= 16) { + Util.sendPluginMessage(sender, "&7(Attempting UUID lookup, since you specified a user)"); + + plugin.getDatastore().getUUID(user, uuid -> { + if (uuid == null) { + Util.sendPluginMessage(sender, "&eUser could not be found."); + return; + } + runSub(plugin, sender, uuid, sub, strippedArgs); + }); + return; + } + + Util.sendPluginMessage(sender, "&d" + user + "&c is not a valid username/uuid."); + } + + private void runSub(LuckPermsPlugin plugin, Sender sender, UUID uuid, UserSubCommand command, List strippedArgs) { + plugin.getDatastore().loadUser(uuid, success -> { + if (!success) { + Util.sendPluginMessage(sender, "&eUser could not be found."); + return; + } + + User user1 = plugin.getUserManager().getUser(uuid); + + if (user1 == null) { + Util.sendPluginMessage(sender, "&eUser could not be found."); + } + + if (command.isArgLengthInvalid(strippedArgs.size())) { + command.sendUsage(sender); + return; + } + + command.execute(plugin, sender, user1, strippedArgs); + plugin.getUserManager().cleanupUser(user1); + }); + } + + @Override + public List getSubCommands() { + return subCommands; + } + + public void registerSubCommand(UserSubCommand subCommand) { + subCommands.add(subCommand); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/UserSubCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/UserSubCommand.java new file mode 100644 index 00000000..7362579b --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/UserSubCommand.java @@ -0,0 +1,29 @@ +package me.lucko.luckperms.commands.user; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public abstract class UserSubCommand extends SubCommand { + public UserSubCommand(String name, String description, String usage, String permission) { + super(name, description, usage, permission); + } + + protected abstract void execute(LuckPermsPlugin plugin, Sender sender, User user, List args); + + protected void saveUser(User user, Sender sender, LuckPermsPlugin plugin) { + user.refreshPermissions(); + + plugin.getDatastore().saveUser(user, success -> { + if (success) { + Util.sendPluginMessage(sender, "&7(User data was saved to the datastore)"); + } else { + Util.sendPluginMessage(sender, "There was an error whilst saving the user."); + } + }); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserAddGroupCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserAddGroupCommand.java new file mode 100644 index 00000000..bb40e6c5 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserAddGroupCommand.java @@ -0,0 +1,49 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserAddGroupCommand extends UserSubCommand { + public UserAddGroupCommand() { + super("addgroup", "Adds the user to a group", + "/perms user addgroup [server]", "luckperms.user.addgroup"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + String group = args.get(0).toLowerCase(); + + String server; + if (args.size() != 1) { + server = args.get(1); + } else { + server = "global"; + } + + Group group1 = plugin.getGroupManager().getGroup(group); + if (group1 == null) { + Util.sendPluginMessage(sender, "That group does not exist!"); + return; + } + + try { + user.addGroup(group1, server); + Util.sendPluginMessage(sender, "&b" + user.getName() + "&a successfully added to group &b" + group + "&a on the server &b" + server + "&a."); + } catch (ObjectAlreadyHasException e) { + Util.sendPluginMessage(sender, "The user is already a member of that group."); + } + saveUser(user, sender, plugin); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return (argLength != 1 && argLength != 2); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserClearCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserClearCommand.java new file mode 100644 index 00000000..f657bedf --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserClearCommand.java @@ -0,0 +1,30 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserClearCommand extends UserSubCommand { + public UserClearCommand() { + super("clear", "Clears a users permissions and groups", + "/perms user clear", "luckperms.user.clear"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + user.clearNodes(); + user.getNodes().put(plugin.getConfiguration().getDefaultGroupNode(), true); + Util.sendPluginMessage(sender, "&b" + user.getName() + "&a's permissions were cleared."); + + saveUser(user, sender, plugin); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return false; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserGetUUIDCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserGetUUIDCommand.java new file mode 100644 index 00000000..31f3322d --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserGetUUIDCommand.java @@ -0,0 +1,25 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserGetUUIDCommand extends UserSubCommand { + public UserGetUUIDCommand() { + super("getuuid", "Get the UUID of a user", "/perms user getuuid", "luckperms.user.getuuid"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + Util.sendPluginMessage(sender, "&bThe UUID of &e" + user.getName() + "&b is &e" + user.getUuid().toString() + "&b."); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return false; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserHasPermCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserHasPermCommand.java new file mode 100644 index 00000000..2d66ec1f --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserHasPermCommand.java @@ -0,0 +1,30 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserHasPermCommand extends UserSubCommand { + public UserHasPermCommand() { + super("haspermission", "Checks to see if a user has a certain permission node", + "/perms user haspermission [server]", "luckperms.user.haspermission"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + if (args.size() >= 2) { + Util.sendBoolean(sender, args.get(0), user.hasPermission(args.get(0), true, args.get(1))); + } else { + Util.sendBoolean(sender, args.get(0), user.hasPermission(args.get(0), true, "global")); + } + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return argLength == 0; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserInfoCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserInfoCommand.java new file mode 100644 index 00000000..15938bcb --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserInfoCommand.java @@ -0,0 +1,34 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserInfoCommand extends UserSubCommand { + public UserInfoCommand() { + super("info", "Gives info about the user", + "/perms user info", "luckperms.user.info"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + final String prefix = plugin.getConfiguration().getPrefix(); + String sb = prefix + "&d-> &eUser: &6" + user.getName() + "\n" + + prefix + "&d-> &eUUID: &6" + user.getUuid() + "\n" + + prefix + "&d-> &eStatus: " + plugin.getPlayerStatus(user.getUuid()) + "\n" + + prefix + "&d-> &eGroups: &6" + Util.listToCommaSep(user.getGroupNames()) + "\n" + + prefix + "&d-> &ePermissions: &6" + (user.getNodes().keySet().size() - user.getGroupNames().size()) + "\n" + + prefix + "&d-> &bUse &a/perms user " + user.getName() + " listnodes &bto see all permissions."; + + sender.sendMessage(Util.color(sb)); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return false; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserListNodesCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserListNodesCommand.java new file mode 100644 index 00000000..2b073569 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserListNodesCommand.java @@ -0,0 +1,27 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserListNodesCommand extends UserSubCommand { + public UserListNodesCommand() { + super("listnodes", "Lists the permission nodes the user has", + "/perms user listnodes", "luckperms.user.listnodes"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + Util.sendPluginMessage(sender, "&e" + user.getName() + "'s Nodes:"); + sender.sendMessage(Util.color(Util.nodesToString(user.getNodes()))); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return false; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserRemoveGroupCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserRemoveGroupCommand.java new file mode 100644 index 00000000..9fc07bfd --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserRemoveGroupCommand.java @@ -0,0 +1,49 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.exceptions.ObjectLacksPermissionException; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserRemoveGroupCommand extends UserSubCommand { + public UserRemoveGroupCommand() { + super("removegroup", "Removes a user from a group", + "/perms user removegroup [server]", "luckperms.user.removegroup"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + String group = args.get(0).toLowerCase(); + + String server; + if (args.size() != 1) { + server = args.get(1); + } else { + server = "global"; + } + + Group group1 = plugin.getGroupManager().getGroup(group); + if (group1 == null) { + Util.sendPluginMessage(sender, "That group does not exist!"); + return; + } + + try { + user.removeGroup(group1, server); + Util.sendPluginMessage(sender, "&b" + user.getName() + "&a was removed from group &b" + group + "&a on server &b" + server + "&a."); + } catch (ObjectLacksPermissionException e) { + Util.sendPluginMessage(sender, "The user is not a member of that group."); + } + saveUser(user, sender, plugin); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return (argLength != 1 && argLength != 2); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserSetPermissionCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserSetPermissionCommand.java new file mode 100644 index 00000000..becc0e01 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserSetPermissionCommand.java @@ -0,0 +1,60 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserSetPermissionCommand extends UserSubCommand { + public UserSetPermissionCommand() { + super("set", "Sets a permission for a user", + "/perms user set [server]", "luckperms.user.setpermission"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + String node = args.get(0); + String bool = args.get(1); + + if (node.contains("/")) { + sendUsage(sender); + return; + } + + if (node.matches(".*luckperms\\.group\\..*")) { + Util.sendPluginMessage(sender, "Use the addgroup command instead of specifying the node."); + return; + } + + if (!bool.equalsIgnoreCase("true") && !bool.equalsIgnoreCase("false")) { + sendUsage(sender); + return; + } + + boolean b = Boolean.parseBoolean(bool); + + try { + if (args.size() == 3) { + final String server = args.get(2).toLowerCase(); + user.setPermission(node, b, server); + Util.sendPluginMessage(sender, "&aSet &b" + node + "&a to " + bool + " for &b" + user.getName() + "&a on server &b" + server + "&a."); + } else { + user.setPermission(node, b); + Util.sendPluginMessage(sender, "&aSet &b" + node + "&a to " + bool + " for &b" + user.getName() + "&a."); + } + } catch (ObjectAlreadyHasException e) { + Util.sendPluginMessage(sender, "That user already has this permission!"); + } + + saveUser(user, sender, plugin); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return argLength < 2; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserUnSetPermissionCommand.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserUnSetPermissionCommand.java new file mode 100644 index 00000000..98fddba3 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserUnSetPermissionCommand.java @@ -0,0 +1,51 @@ +package me.lucko.luckperms.commands.user.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.commands.user.UserSubCommand; +import me.lucko.luckperms.exceptions.ObjectLacksPermissionException; +import me.lucko.luckperms.users.User; + +import java.util.List; + +public class UserUnSetPermissionCommand extends UserSubCommand { + public UserUnSetPermissionCommand() { + super("unset", "Unsets a permission for a user", + "/perms user unset [server]", "luckperms.user.unsetpermission"); + } + + @Override + protected void execute(LuckPermsPlugin plugin, Sender sender, User user, List args) { + String node = args.get(0); + + if (node.contains("/")) { + sendUsage(sender); + return; + } + + if (node.matches(".*luckperms\\.group\\..*")) { + Util.sendPluginMessage(sender, "Use the removegroup command instead of specifying the node."); + return; + } + + try { + if (args.size() == 2) { + final String server = args.get(1).toLowerCase(); + user.unsetPermission(node, server); + Util.sendPluginMessage(sender, "&aUnset &b" + node + "&a for &b" + user.getName() + "&a on server &b" + server + "&a."); + } else { + user.unsetPermission(node); + Util.sendPluginMessage(sender, "&aUnset &b" + node + "&a for &b" + user.getName() + "&a."); + } + } catch (ObjectLacksPermissionException e) { + Util.sendPluginMessage(sender, "That user does not have this permission set."); + } + saveUser(user, sender, plugin); + } + + @Override + public boolean isArgLengthInvalid(int argLength) { + return argLength == 0; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/data/Datastore.java b/common/src/main/java/me/lucko/luckperms/data/Datastore.java new file mode 100644 index 00000000..8404d844 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/data/Datastore.java @@ -0,0 +1,117 @@ +package me.lucko.luckperms.data; + +import lombok.Getter; +import lombok.Setter; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.users.User; + +import java.util.UUID; + +public abstract class Datastore { + protected final LuckPermsPlugin plugin; + + @Getter + public String name; + + @Getter + @Setter + private boolean acceptingLogins; + + public Datastore(LuckPermsPlugin plugin, String name) { + this.plugin = plugin; + this.name = name; + this.acceptingLogins = true; + } + + /** + * Execute a runnable asynchronously + * @param r the task to run + */ + private void doAsync(Runnable r) { + plugin.doAsync(r); + } + + /** + * Execute a runnable synchronously + * @param r the task to run + */ + private void doSync(Runnable r) { + plugin.doSync(r); + } + + private void runCallback(boolean result, Callback callback) { + doSync(() -> callback.onComplete(result)); + } + + /* + These methods will block the thread that they're ran on. + */ + public abstract void init(DatastoreConfiguration configuration); + public abstract boolean loadOrCreateUser(UUID uuid, String username); + public abstract boolean loadUser(UUID uuid); + public abstract boolean saveUser(User user); + public abstract boolean createAndLoadGroup(String name); + public abstract boolean loadGroup(String name); + public abstract boolean loadAllGroups(); + public abstract boolean saveGroup(Group group); + public abstract boolean deleteGroup(Group group); + public abstract boolean saveUUIDData(String username, UUID uuid); + public abstract UUID getUUID(String username); + + + + /* + These methods will return as soon as they are called. The callback will be ran when the task is complete + They therefore will not block the thread that they're ran on + + Callbacks are ran on the main server thread (if applicable) + */ + public void loadOrCreateUser(UUID uuid, String username, Callback callback) { + doAsync(() -> runCallback(loadOrCreateUser(uuid, username), callback)); + } + + public void loadUser(UUID uuid, Callback callback) { + doAsync(() -> runCallback(loadUser(uuid), callback)); + } + + public void saveUser(User user, Callback callback) { + doAsync(() -> runCallback(saveUser(user), callback)); + } + + public void createAndLoadGroup(String name, Callback callback) { + doAsync(() -> runCallback(createAndLoadGroup(name), callback)); + } + + public void loadGroup(String name, Callback callback) { + doAsync(() -> runCallback(loadGroup(name), callback)); + } + + public void loadAllGroups(Callback callback) { + doAsync(() -> runCallback(loadAllGroups(), callback)); + } + + public void saveGroup(Group group, Callback callback) { + doAsync(() -> runCallback(saveGroup(group), callback)); + } + + public void deleteGroup(Group group, Callback callback) { + doAsync(() -> runCallback(deleteGroup(group), callback)); + } + + public void saveUUIDData(String username, UUID uuid, Callback callback) { + doAsync(() -> runCallback(saveUUIDData(username, uuid), callback)); + } + + public void getUUID(String username, GetUUIDCallback callback) { + doAsync(() -> doSync(() -> callback.onComplete(getUUID(username)))); + } + + public interface Callback { + void onComplete(boolean success); + } + + public interface GetUUIDCallback { + void onComplete(UUID uuid); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/data/DatastoreConfiguration.java b/common/src/main/java/me/lucko/luckperms/data/DatastoreConfiguration.java new file mode 100644 index 00000000..241576f1 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/data/DatastoreConfiguration.java @@ -0,0 +1,15 @@ +package me.lucko.luckperms.data; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class DatastoreConfiguration { + + private final String address; + private final String database; + private final String username; + private final String password; + +} diff --git a/common/src/main/java/me/lucko/luckperms/data/HikariDatastore.java b/common/src/main/java/me/lucko/luckperms/data/HikariDatastore.java new file mode 100644 index 00000000..5a3f445f --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/data/HikariDatastore.java @@ -0,0 +1,338 @@ +package me.lucko.luckperms.data; + +import com.zaxxer.hikari.HikariDataSource; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.groups.GroupManager; +import me.lucko.luckperms.users.User; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; + +public class HikariDatastore extends Datastore { + + private static final String CREATETABLE_UUID = "CREATE TABLE IF NOT EXISTS `lp_uuid` (`name` VARCHAR(16) NOT NULL, `uuid` VARCHAR(36) NOT NULL, PRIMARY KEY (`name`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;"; + private static final String CREATETABLE_USERS = "CREATE TABLE IF NOT EXISTS `lp_users` (`uuid` VARCHAR(36) NOT NULL, `name` VARCHAR(16) NOT NULL, `perms` TEXT NOT NULL, PRIMARY KEY (`uuid`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;"; + private static final String CREATETABLE_GROUPS = "CREATE TABLE IF NOT EXISTS `lp_groups` (`name` VARCHAR(36) NOT NULL, `perms` TEXT NULL, PRIMARY KEY (`name`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;"; + + private static final String USER_INSERT = "INSERT INTO lp_users VALUES(?, ?, ?) ON DUPLICATE KEY UPDATE name=?"; + private static final String USER_SELECT = "SELECT * FROM lp_users WHERE uuid=?"; + private static final String USER_SAVE = "UPDATE lp_users SET name=?, perms=? WHERE uuid=?"; + + private static final String GROUP_INSERT = "INSERT INTO lp_groups VALUES(?, ?) ON DUPLICATE KEY UPDATE perms=?"; + private static final String GROUP_SELECT = "SELECT perms FROM lp_groups WHERE name=?"; + private static final String GROUP_SELECT_ALL = "SELECT * FROM lp_groups"; + private static final String GROUP_SAVE = "UPDATE lp_groups SET perms=? WHERE name=?"; + private static final String GROUP_DELETE = "DELETE FROM lp_groups WHERE name=?"; + + private static final String UUIDCACHE_INSERT = "INSERT INTO lp_uuid VALUES(?, ?) ON DUPLICATE KEY UPDATE uuid=?"; + private static final String UUIDCACHE_SELECT = "SELECT uuid FROM lp_uuid WHERE name=?"; + + private HikariDataSource hikari; + + public HikariDatastore(LuckPermsPlugin plugin) { + super(plugin, "MySQL"); + } + + private static void executeQuery(Connection connection, String query) throws SQLException { + PreparedStatement preparedStatement = connection.prepareStatement(query); + preparedStatement.execute(); + preparedStatement.close(); + } + + private boolean runQuery(Query query) { + boolean success = false; + + Connection connection = null; + try { + connection = hikari.getConnection(); + success = query.onRun(connection); + } catch (SQLException e) { + e.printStackTrace(); + success = false; + } finally { + if (connection != null) { + try { + connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + return success; + } + + private void setupTables() { + boolean success = runQuery(connection -> { + executeQuery(connection, CREATETABLE_UUID); + executeQuery(connection, CREATETABLE_USERS); + executeQuery(connection, CREATETABLE_GROUPS); + return true; + }); + + if (!success) { + plugin.getLogger().log(Level.SEVERE, "Error occurred whilst connecting to the database. All connections are disallowed."); + hikari.shutdown(); + setAcceptingLogins(false); + } + } + + @Override + public void init(DatastoreConfiguration configuration) { + hikari = new HikariDataSource(); + + final String address = configuration.getAddress(); + final String database = configuration.getDatabase(); + final String username = configuration.getUsername(); + final String password = configuration.getPassword(); + + hikari.setMaximumPoolSize(10); + hikari.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); + hikari.addDataSourceProperty("serverName", address.split(":")[0]); + hikari.addDataSourceProperty("port", address.split(":")[1]); + hikari.addDataSourceProperty("databaseName", database); + hikari.addDataSourceProperty("user", username); + hikari.addDataSourceProperty("password", password); + + setupTables(); + } + + @Override + public boolean loadUser(UUID uuid) { + User user = plugin.getUserManager().makeUser(uuid); + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(USER_SELECT); + preparedStatement.setString(1, uuid.toString()); + + ResultSet resultSet = preparedStatement.executeQuery(); + List nodes = new ArrayList<>(); + + if (resultSet.next()) { + if (!resultSet.getString("perms").equals("#")) { + nodes.addAll(Arrays.asList(resultSet.getString("perms").split(":"))); + } + user.setName(resultSet.getString("name")); + + user.loadNodes(nodes); + preparedStatement.close(); + resultSet.close(); + return true; + } + preparedStatement.close(); + resultSet.close(); + return false; + }); + + if (success) plugin.getUserManager().updateOrSetUser(user); + return success; + } + + @Override + public boolean loadOrCreateUser(UUID uuid, String username) { + User user = plugin.getUserManager().makeUser(uuid, username); + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(USER_INSERT); + preparedStatement.setString(1, uuid.toString()); + preparedStatement.setString(2, username); + preparedStatement.setString(3, plugin.getConfiguration().getDefaultGroupNode()); + preparedStatement.setString(4, username); + preparedStatement.execute(); + preparedStatement.close(); + + preparedStatement = connection.prepareStatement(USER_SELECT); + preparedStatement.setString(1, uuid.toString()); + + ResultSet resultSet = preparedStatement.executeQuery(); + List nodes = new ArrayList<>(); + + if (resultSet.next()) { + if (!resultSet.getString("perms").equals("#")) { + nodes.addAll(Arrays.asList(resultSet.getString("perms").split(":"))); + } + user.loadNodes(nodes); + preparedStatement.close(); + resultSet.close(); + return true; + } + preparedStatement.close(); + resultSet.close(); + return true; + }); + + if (success) plugin.getUserManager().updateOrSetUser(user); + return success; + } + + @Override + public boolean saveUser(User user) { + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(USER_SAVE); + preparedStatement.setString(1, user.getName()); + preparedStatement.setString(2, user.serializeNodes()); + preparedStatement.setString(3, user.getUuid().toString()); + preparedStatement.execute(); + preparedStatement.close(); + return true; + }); + return success; + } + + @Override + public boolean createAndLoadGroup(String name) { + Group group = plugin.getGroupManager().makeGroup(name); + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(GROUP_INSERT); + preparedStatement.setString(1, name); + preparedStatement.setString(2, "#"); + preparedStatement.setString(3, "#"); + preparedStatement.execute(); + preparedStatement.close(); + + preparedStatement = connection.prepareStatement(GROUP_SELECT); + preparedStatement.setString(1, name); + + ResultSet resultSet = preparedStatement.executeQuery(); + List nodes = new ArrayList<>(); + + if (resultSet.next()) { + if (!resultSet.getString("perms").equals("#")) { + nodes.addAll(Arrays.asList(resultSet.getString("perms").split(":"))); + } + } + + group.loadNodes(nodes); + preparedStatement.close(); + resultSet.close(); + return true; + }); + if (success) plugin.getGroupManager().updateOrSetGroup(group); + return success; + } + + @Override + public boolean loadGroup(String name) { + Group group = plugin.getGroupManager().makeGroup(name); + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(GROUP_SELECT); + preparedStatement.setString(1, name); + + ResultSet resultSet = preparedStatement.executeQuery(); + List nodes = new ArrayList<>(); + + if (resultSet.next()) { + if (!resultSet.getString("perms").equals("#")) { + nodes.addAll(Arrays.asList(resultSet.getString("perms").split(":"))); + } + + group.loadNodes(nodes); + return true; + } + preparedStatement.close(); + resultSet.close(); + return false; + }); + if (success) plugin.getGroupManager().updateOrSetGroup(group); + return success; + } + + @Override + public boolean loadAllGroups() { + List groups = new ArrayList<>(); + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(GROUP_SELECT_ALL); + + ResultSet resultSet = preparedStatement.executeQuery(); + + while (resultSet.next()) { + Group group = plugin.getGroupManager().makeGroup(resultSet.getString("name")); + if (!resultSet.getString("perms").equals("#")) { + group.loadNodes(Arrays.asList(resultSet.getString("perms").split(":"))); + } + groups.add(group); + } + preparedStatement.close(); + resultSet.close(); + return true; + }); + + GroupManager gm = plugin.getGroupManager(); + if (success) { + groups.forEach(gm::setGroup); + } + return success; + } + + @Override + public boolean saveGroup(Group group) { + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(GROUP_SAVE); + preparedStatement.setString(1, group.serializeNodes()); + preparedStatement.setString(2, group.getName()); + preparedStatement.execute(); + preparedStatement.close(); + return true; + }); + return success; + } + + @Override + public boolean deleteGroup(Group group) { + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(GROUP_DELETE); + preparedStatement.setString(1, group.getName()); + preparedStatement.execute(); + preparedStatement.close(); + return true; + }); + if (success) plugin.getGroupManager().unloadGroup(group); + return success; + } + + @Override + public boolean saveUUIDData(String username, UUID uuid) { + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(UUIDCACHE_INSERT); + preparedStatement.setString(1, username); + preparedStatement.setString(2, uuid.toString()); + preparedStatement.setString(3, uuid.toString()); + preparedStatement.execute(); + preparedStatement.close(); + return true; + }); + return success; + } + + @Override + public UUID getUUID(String username) { + final UUID[] uuid = {null}; + boolean success = runQuery(connection -> { + PreparedStatement preparedStatement = connection.prepareStatement(UUIDCACHE_SELECT); + preparedStatement.setString(1, username); + ResultSet resultSet = preparedStatement.executeQuery(); + + if (resultSet.next()) { + uuid[0] = UUID.fromString(resultSet.getString("uuid")); + preparedStatement.close(); + resultSet.close(); + return true; + } + + preparedStatement.close(); + resultSet.close(); + return false; + }); + + return success ? uuid[0] : null; + } + + private interface Query { + boolean onRun(Connection connection) throws SQLException; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/exceptions/ObjectAlreadyHasException.java b/common/src/main/java/me/lucko/luckperms/exceptions/ObjectAlreadyHasException.java new file mode 100644 index 00000000..b797019b --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/exceptions/ObjectAlreadyHasException.java @@ -0,0 +1,4 @@ +package me.lucko.luckperms.exceptions; + +public class ObjectAlreadyHasException extends Exception { +} diff --git a/common/src/main/java/me/lucko/luckperms/exceptions/ObjectLacksPermissionException.java b/common/src/main/java/me/lucko/luckperms/exceptions/ObjectLacksPermissionException.java new file mode 100644 index 00000000..c94f78e2 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/exceptions/ObjectLacksPermissionException.java @@ -0,0 +1,4 @@ +package me.lucko.luckperms.exceptions; + +public class ObjectLacksPermissionException extends Exception { +} diff --git a/common/src/main/java/me/lucko/luckperms/groups/Group.java b/common/src/main/java/me/lucko/luckperms/groups/Group.java new file mode 100644 index 00000000..df2791da --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/groups/Group.java @@ -0,0 +1,31 @@ +package me.lucko.luckperms.groups; + +import lombok.Getter; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.utils.PermissionObject; + +public class Group extends PermissionObject { + + /** + * The name of the group + */ + @Getter + private final String name; + + public Group(String name, LuckPermsPlugin plugin) { + super(plugin, name); + this.name = name; + } + + /** + * Clear all of the groups permission nodes + */ + public void clearNodes() { + getNodes().clear(); + } + + @Override + public String toString() { + return getName(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/groups/GroupManager.java b/common/src/main/java/me/lucko/luckperms/groups/GroupManager.java new file mode 100644 index 00000000..07b7d228 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/groups/GroupManager.java @@ -0,0 +1,93 @@ +package me.lucko.luckperms.groups; + +import lombok.Getter; +import me.lucko.luckperms.LuckPermsPlugin; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class GroupManager { + private final LuckPermsPlugin plugin; + + /** + * A {@link Map} containing all loaded groups + */ + @Getter + private final Map groups = new ConcurrentHashMap<>(); + + public GroupManager(LuckPermsPlugin plugin) { + this.plugin = plugin; + loadAllGroups(); + } + + /** + * Get a group object by name + * @param name The name to search by + * @return a {@link Group} object if the group is loaded, returns null if the group is not loaded + */ + public Group getGroup(String name) { + return groups.get(name); + } + + /** + * Add a group to the loaded groups map + * @param group The group to add + */ + public void setGroup(Group group) { + groups.put(group.getName(), group); + } + + /** + * Updates (or sets if the group wasn't already loaded) a group in the groups map + * @param group The group to update or set + */ + public void updateOrSetGroup(Group group) { + if (!groups.containsKey(group.getName())) { + // The group isn't already loaded + groups.put(group.getName(), group); + } else { + groups.get(group.getName()).setNodes(group.getNodes()); + } + } + + /** + * Check to see if a group is loaded or not + * @param name The name of the group + * @return true if the group is loaded + */ + public boolean isLoaded(String name) { + return groups.containsKey(name); + } + + /** + * Removes and unloads the group from the plugins internal storage + * @param group The group to unload + */ + public void unloadGroup(Group group) { + if (group != null) { + groups.remove(group.getName()); + } + } + + /** + * Load all groups from the datastore + */ + public void loadAllGroups() { + plugin.getDatastore().loadAllGroups(success -> { + String defaultGroup = plugin.getConfiguration().getDefaultGroupName(); + + if (!groups.keySet().contains(defaultGroup)) { + plugin.getDatastore().createAndLoadGroup(defaultGroup, success1 -> {}); + } + }); + } + + /** + * Makes a new group object + * @param name The name of the group + * @return a new {@link Group} object + */ + public Group makeGroup(String name) { + return new Group(name, plugin); + } +} \ No newline at end of file diff --git a/common/src/main/java/me/lucko/luckperms/users/User.java b/common/src/main/java/me/lucko/luckperms/users/User.java new file mode 100644 index 00000000..6eb360ed --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/users/User.java @@ -0,0 +1,197 @@ +package me.lucko.luckperms.users; + +import lombok.Getter; +import lombok.Setter; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.exceptions.ObjectLacksPermissionException; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.utils.PermissionObject; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public abstract class User extends PermissionObject { + + /** + * The users Mojang UUID + */ + @Getter + private final UUID uuid; + + /** + * The last known username of a player + */ + @Getter + @Setter + private String name; + + public User(UUID uuid, LuckPermsPlugin plugin) { + super(plugin, uuid.toString()); + this.uuid = uuid; + this.name = null; + } + + public User(UUID uuid, String name, LuckPermsPlugin plugin) { + super(plugin, uuid.toString()); + this.uuid = uuid; + this.name = name; + } + + /** + * Refresh and re-assign the users permissions + */ + public abstract void refreshPermissions(); + + /** + * Check to see if the user is a member of a group + * @param group The group to check membership of + * @return true if the user is a member of the group + */ + public boolean isInGroup(Group group) { + return isInGroup(group, "global"); + } + + /** + * Check to see if a user is a member of a group on a specific server + * @param group The group to check membership of + * @param server The server to check on + * @return true if the user is a member of the group + */ + public boolean isInGroup(Group group, String server) { + return getLocalGroups(server).contains(group.getName()); + } + + /** + * Add a user to a group + * @param group The group to add the user to + * @throws ObjectAlreadyHasException if the user is already a member of the group + */ + public void addGroup(Group group) throws ObjectAlreadyHasException { + addGroup(group, "global"); + } + + /** + * Add a user to a group on a specific server + * @param group The group to add the user to + * @param server The server to add the group on + * @throws ObjectAlreadyHasException if the user is already a member of the group on that server + */ + public void addGroup(Group group, String server) throws ObjectAlreadyHasException { + if (server == null) { + server = "global"; + } + + if (isInGroup(group, server)) { + throw new ObjectAlreadyHasException(); + } + + if (server.equalsIgnoreCase("global")) { + getNodes().put("luckperms.group." + group.getName(), true); + } else { + getNodes().put(server + "/luckperms.group." + group.getName(), true); + } + } + + /** + * Remove the user from a group + * @param group the group to remove the user from + * @throws ObjectLacksPermissionException + */ + public void removeGroup(Group group) throws ObjectLacksPermissionException { + removeGroup(group, "global"); + } + + /** + * Remove the user from a group + * @param group The group to remove the user from + * @param server The server to remove the group on + * @throws ObjectLacksPermissionException if the user isn't a member of the group + */ + public void removeGroup(Group group, String server) throws ObjectLacksPermissionException { + if (server == null) { + server = "global"; + } + + if (!getLocalGroups(server).contains(group.getName())) { + throw new ObjectLacksPermissionException(); + } + + if (server.equalsIgnoreCase("global")) { + getNodes().remove("luckperms.group." + group.getName()); + } else { + getNodes().remove(server + "/luckperms.group." + group.getName()); + } + } + + /** + * Clear all of the users permission nodes + */ + public void clearNodes() { + String defaultGroupNode = getPlugin().getConfiguration().getDefaultGroupNode(); + getNodes().clear(); + getNodes().put(defaultGroupNode, true); + } + + /** + * Get a {@link List} of all of the groups the user is a member of, on all servers + * @return a {@link List} of group names + */ + public List getGroupNames() { + return getGroups(null, true, true); + } + + /** + * Get a {@link List} of the groups the user is a member of on a specific server + * @param server the server to check + * @return a {@link List} of group names + */ + public List getLocalGroups(String server) { + return getGroups(server, false, false); + } + + /** + * Get a {@link List} of the groups the user is a member of on a specific server with the option to include global groups or all groups + * @param server Which server to check on + * @param includeGlobal Whether to include global groups + * @param includeAll Whether to get all groups + * @return a {@link List} of group names + */ + public List getGroups(String server, boolean includeGlobal, boolean includeAll) { + List groups = new ArrayList<>(); + + if (server == null || server.equals("")) { + server = "global"; + } + + for (String node : getNodes().keySet()) { + String originalNode = node; + // Has a defined server + if (node.contains("/")) { + String[] parts = node.split("\\/", 2); + if (!parts[0].equalsIgnoreCase(server) && !includeAll) { + continue; + } + node = parts[1]; + } else { + if (!includeGlobal) { + continue; + } + } + + if (node.matches("luckperms\\.group\\..*")) { + if (getNodes().get(originalNode)) { + String groupName = node.split("\\.", 3)[2]; + groups.add(groupName); + } + } + } + return groups; + } + + @Override + public String toString() { + return getUuid().toString(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/users/UserManager.java b/common/src/main/java/me/lucko/luckperms/users/UserManager.java new file mode 100644 index 00000000..e4cd700e --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/users/UserManager.java @@ -0,0 +1,120 @@ +package me.lucko.luckperms.users; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.Util; +import me.lucko.luckperms.data.Datastore; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +@NoArgsConstructor +public abstract class UserManager { + + /** + * A {@link Map} containing all online/loaded users + */ + @Getter + private final Map users = new ConcurrentHashMap<>(); + + /** + * Get a user object by UUID + * @param uuid The uuid to search by + * @return a {@link User} object if the user is loaded, returns null if the user is not loaded + */ + public User getUser(UUID uuid) { + return users.get(uuid); + } + + /** + * Get a user object by name + * @param name The name to search by + * @return a {@link User} object if the user is loaded, returns null if the user is not loaded + */ + public User getUser(String name) { + User user = null; + + for (User u : users.values()) { + if (u.getName().equalsIgnoreCase(name)) { + user = u; + break; + } + } + + return user; + } + + /** + * Add a user to the {@link #getUsers()} map + * @param user the user to add + */ + public void setUser(User user) { + users.put(user.getUuid(), user); + } + + /** + * Updates (or sets if the user wasn't already loaded) a user in the {@link #getUsers()} map + * @param user The user to update or set + */ + public void updateOrSetUser(User user) { + if (!users.containsKey(user.getUuid())) { + // The user isn't already loaded, so we can just add + users.put(user.getUuid(), user); + // They're probably not online, but in case they are... + user.refreshPermissions(); + } else { + // Override the user's current loaded nodes, and force a refresh + users.get(user.getUuid()).setNodes(user.getNodes()); + users.get(user.getUuid()).refreshPermissions(); + } + } + + /** + * Saves a user object in the datastore + * @param user the user to save + * @param datastore the datastore + */ + public void saveUser(User user, Datastore datastore) { + user.refreshPermissions(); + datastore.saveUser(user, success -> {}); + } + + /** + * Check to see if a user is loaded or not + * @param uuid the UUID of the user + * @return true if the user is loaded + */ + public boolean isLoaded(UUID uuid) { + return users.containsKey(uuid); + } + + /** + * Removes and unloads any permission links of the user from the internal storage + * @param user The user to unload + */ + public abstract void unloadUser(User user); + + /** + * Checks to see if the user is online, and if they are not, runs {@link #unloadUser(User)} + * @param user The user to be cleaned up + */ + public abstract void cleanupUser(User user); + + /** + * Makes a new {@link User} object + * @param uuid The UUID of the user + * @return a new {@link User} object + */ + public abstract User makeUser(UUID uuid); + + /** + * Makes a new {@link User} object + * @param uuid The UUID of the user + * @param username The username of the user + * @return a new {@link User} object + */ + public abstract User makeUser(UUID uuid, String username); +} diff --git a/common/src/main/java/me/lucko/luckperms/utils/LPConfiguration.java b/common/src/main/java/me/lucko/luckperms/utils/LPConfiguration.java new file mode 100644 index 00000000..f8fa666c --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/utils/LPConfiguration.java @@ -0,0 +1,13 @@ +package me.lucko.luckperms.utils; + +public interface LPConfiguration { + + String getServer(); + String getPrefix(); + int getSyncTime(); + String getDefaultGroupNode(); + String getDefaultGroupName(); + boolean getIncludeGlobalPerms(); + String getDatabaseValue(String value); + +} diff --git a/common/src/main/java/me/lucko/luckperms/utils/PermissionObject.java b/common/src/main/java/me/lucko/luckperms/utils/PermissionObject.java new file mode 100644 index 00000000..4fb7b174 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/utils/PermissionObject.java @@ -0,0 +1,234 @@ +package me.lucko.luckperms.utils; + +import lombok.Getter; +import lombok.Setter; +import lombok.NonNull; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.exceptions.ObjectLacksPermissionException; +import me.lucko.luckperms.groups.Group; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Represents an object that can hold permissions + * For example a User or a Group + */ +@Getter +public abstract class PermissionObject { + + /** + * The UUID of the user / name of the group. + * Used to prevent circular inheritance issues + */ + private final String objectName; + + /** + * Reference to the main plugin instance + */ + private final LuckPermsPlugin plugin; + + /** + * If false, only permissions specific to the server are applied + */ + @Setter + + private boolean includeGlobalPermissions; + + /** + * The user/group's permissions + */ + @Setter + private Map nodes = new HashMap<>(); + + public PermissionObject(LuckPermsPlugin plugin, String objectName) { + this.objectName = objectName; + this.plugin = plugin; + this.includeGlobalPermissions = plugin.getConfiguration().getIncludeGlobalPerms(); + } + + /** + * Checks to see if the object has a certain permission + * @param node The permission node + * @param b If the node is true/false(negated) + * @return true if the user has the permission + */ + public boolean hasPermission(String node, Boolean b) { + if (node.startsWith("global/")) node = node.replace("global/", ""); + if (b) { + return getNodes().containsKey(node) && getNodes().get(node); + } + return getNodes().containsKey(node) && !getNodes().get(node); + } + + /** + * Checks to see the the object has a permission on a certain server + * @param node The permission node + * @param b If the node is true/false(negated) + * @param server The server + * @return true if the user has the permission + */ + public boolean hasPermission(String node, Boolean b, String server) { + return hasPermission(server + "/" + node, b); + } + + /** + * Sets a permission for the object + * @param node The node to be set + * @param value What to set the node to - true/false(negated) + * @throws ObjectAlreadyHasException if the object already has the permission + */ + public void setPermission(String node, Boolean value) throws ObjectAlreadyHasException { + if (node.startsWith("global/")) node = node.replace("global/", ""); + if (hasPermission(node, value)) { + throw new ObjectAlreadyHasException(); + } + getNodes().put(node, value); + } + + /** + * Sets a permission for the object + * @param node The node to set + * @param value What to set the node to - true/false(negated) + * @param server The server to set the permission on + * @throws ObjectAlreadyHasException if the object already has the permission + */ + public void setPermission(String node, Boolean value, String server) throws ObjectAlreadyHasException { + setPermission(server + "/" + node, value); + } + + /** + * Unsets a permission for the object + * @param node The node to be unset + * @throws ObjectLacksPermissionException if the node wasn't already set + */ + public void unsetPermission(String node) throws ObjectLacksPermissionException { + if (node.startsWith("global/")) node = node.replace("global/", ""); + if (!getNodes().containsKey(node)) { + throw new ObjectLacksPermissionException(); + } + + getNodes().remove(node); + } + + /** + * Unsets a permission for the object + * @param node The node to be unset + * @param server The server to unset the node on + * @throws ObjectLacksPermissionException if the node wasn't already set + */ + public void unsetPermission(String node, String server) throws ObjectLacksPermissionException { + unsetPermission(server + "/" + node); + } + + /** + * Gets the permissions and inherited permissions that apply to a specific server + * @param server The server to get nodes for + * @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues) + * @return a {@link Map} of the permissions + */ + public Map getLocalPermissions(String server, List excludedGroups) { + return getPermissions(server, excludedGroups, includeGlobalPermissions); + + } + + private Map getPermissions(String server, List excludedGroups, boolean includeGlobal) { + if (excludedGroups == null) { + excludedGroups = new ArrayList<>(); + } + + excludedGroups.add(getObjectName()); + Map perms = new HashMap<>(); + + if (server == null || server.equals("")) { + server = "global"; + } + + for (String node : getNodes().keySet()) { + String originalNode = node; + // Has a defined server + if (node.contains("/")) { + String[] parts = node.split("\\/", 2); + if (!parts[0].equalsIgnoreCase(server)) { + continue; + } + node = parts[1]; + + perms.put(node, getNodes().get(originalNode)); + continue; + } + + if (node.matches("luckperms\\.group\\..*")) { + if (getNodes().get(originalNode)) { + String groupName = node.split("\\.", 3)[2]; + Group group = plugin.getGroupManager().getGroup(groupName); + + if (!excludedGroups.contains(groupName)) { + if (group != null) { + perms.putAll(group.getLocalPermissions(server, excludedGroups)); + } else { + plugin.getLogger().warning("Error whilst refreshing the permissions of '" + objectName + "'." + + "\n The group '" + groupName + "' is not loaded."); + } + } + } + + perms.put(node, getNodes().get(originalNode)); + continue; + } + + if (includeGlobal) perms.put(node, getNodes().get(originalNode)); + } + return perms; + } + + /** + * Loads a list of semi-serialised nodes into the object + * @param data The data to be loaded + */ + public void loadNodes(List data) { + // String is the node in format "server/plugin.command-false" or "plugin.command-false" or "server/plugin.command" + // or just "plugin.command" + + for (String s : data) { + String[] parts = s.split("-", 2); + + if (parts.length == 2) { + nodes.put(parts[0], Boolean.valueOf(parts[1])); + } else { + nodes.put(parts[0], true); + } + } + } + + /** + * Convert the permission nodes map to a list of strings + * @return a {@link List} of nodes + */ + public List getNodesAsString() { + List data = new ArrayList<>(); + + for (String node : nodes.keySet()) { + if (nodes.get(node)) { + data.add(node); + } else { + data.add(node + "-false"); + } + } + + return data; + } + + /** + * Serialize the nodes in the object to be saved in the datastore + * @return A serialized string + */ + public String serializeNodes() { + if (nodes.isEmpty()) return "#"; + return getNodesAsString().stream().collect(Collectors.joining(":")); + } +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..65efe13a --- /dev/null +++ b/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + me.lucko + luckperms + 1.0-SNAPSHOT + + bukkit + common + bungee + + + pom + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + oss-sonatype-snapshots + https://oss.sonatype.org/content/repositories/snapshots/ + + + vault-repo + http://nexus.theyeticave.net/content/repositories/pub_releases + + + + + + + com.zaxxer + HikariCP-java6 + 2.0.1 + compile + + + + org.javassist + javassist + 3.18.1-GA + + + + org.slf4j + slf4j-simple + 1.7.5 + + + + org.projectlombok + lombok + 1.16.8 + provided + + + \ No newline at end of file