From dd7aee9d156b74a6465ad00282ee14ccf910c68b Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 21 Aug 2016 22:20:14 +0100 Subject: [PATCH] Partially add migration support --- .../me/lucko/luckperms/LPBukkitPlugin.java | 20 + .../me/lucko/luckperms/LPBungeePlugin.java | 23 + common/pom.xml | 31 ++ .../me/lucko/luckperms/LuckPermsPlugin.java | 32 ++ .../luckperms/commands/CommandManager.java | 1 + .../lucko/luckperms/commands/MainCommand.java | 2 +- .../migration/MigrationMainCommand.java | 91 ++++ .../subcommands/MigrationGroupManager.java | 59 +++ .../subcommands/MigrationPermissionsEx.java | 178 ++++++++ .../subcommands/MigrationPowerfulPerms.java | 411 ++++++++++++++++++ .../subcommands/MigrationZPermissions.java | 138 ++++++ .../me/lucko/luckperms/constants/Message.java | 4 +- .../lucko/luckperms/constants/Permission.java | 4 +- pom.xml | 8 + .../me/lucko/luckperms/LPSpongePlugin.java | 20 + 15 files changed, 1019 insertions(+), 3 deletions(-) create mode 100644 common/src/main/java/me/lucko/luckperms/commands/migration/MigrationMainCommand.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationGroupManager.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPermissionsEx.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPowerfulPerms.java create mode 100644 common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationZPermissions.java diff --git a/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java index 545d374ac..11949eb4f 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java @@ -156,6 +156,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { return getDescription().getVersion(); } + @Override + public Type getType() { + return Type.BUKKIT; + } + @Override public File getMainDir() { return getDataFolder(); @@ -198,6 +203,21 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { return perms; } + @Override + public Object getPlugin(String name) { + return getServer().getPluginManager().getPlugin(name); + } + + @Override + public Object getService(Class clazz) { + return getServer().getServicesManager().load(clazz); + } + + @Override + public boolean isPluginLoaded(String name) { + return getServer().getPluginManager().isPluginEnabled(name); + } + @Override public void runUpdateTask() { getServer().getScheduler().runTaskAsynchronously(this, new UpdateTask(this)); diff --git a/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java index 39b594116..00a5f0e64 100644 --- a/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java +++ b/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java @@ -126,6 +126,11 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { return getDescription().getVersion(); } + @Override + public Type getType() { + return Type.BUNGEE; + } + @Override public File getMainDir() { return getDataFolder(); @@ -162,6 +167,24 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { return Collections.emptyList(); } + @Override + public Object getPlugin(String name) { + return getProxy().getPluginManager().getPlugin(name); + } + + @Override + public Object getService(Class clazz) { + return null; + } + + @Override + public boolean isPluginLoaded(String name) { + return getProxy().getPluginManager().getPlugins().stream() + .filter(p -> p.getDescription().getName().equalsIgnoreCase(name)) + .findAny() + .isPresent(); + } + @Override public void runUpdateTask() { doAsync(new UpdateTask(this)); diff --git a/common/pom.xml b/common/pom.xml index 6c3303dca..80b4dd495 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -88,6 +88,37 @@ 1.16.10 provided + + + org.tyrannyofheaven.bukkit + zPermissions + 1.3 + provided + + + ru.tehkode + PermissionsEx + 1.23 + provided + + + org.bukkit + bukkit + + + + + com.github.cheesesoftware + PowerfulPermsAPI + 1.0.1 + provided + + + org.anjocaido + GroupManager + 1.4 + provided + diff --git a/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java index e339f9f8a..85cfda786 100644 --- a/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java @@ -63,6 +63,12 @@ public interface LuckPermsPlugin { */ String getVersion(); + + /** + * @return the platform type + */ + Type getType(); + /** * @return the main plugin directory */ @@ -114,6 +120,27 @@ public interface LuckPermsPlugin { */ Set getIgnoringLogs(); + /** + * Gets a loaded plugins instance from the platform + * @param name the name of the plugin + * @return a plugin instance + */ + Object getPlugin(String name); + + /** + * Gets a provided service from the platform. + * @param clazz the class of the service + * @return the service instance, if it is provided for + */ + Object getService(Class clazz); + + /** + * Checks if a plugin is loaded on the platform + * @param name the name of the plugin + * @return true if the plugin is loaded + */ + boolean isPluginLoaded(String name); + /** * Runs an update task */ @@ -130,4 +157,9 @@ public interface LuckPermsPlugin { * @param r the task to run */ void doSync(Runnable r); + + + enum Type { + BUKKIT, BUNGEE, SPONGE; + } } diff --git a/common/src/main/java/me/lucko/luckperms/commands/CommandManager.java b/common/src/main/java/me/lucko/luckperms/commands/CommandManager.java index 38a6208d5..58ca429c0 100644 --- a/common/src/main/java/me/lucko/luckperms/commands/CommandManager.java +++ b/common/src/main/java/me/lucko/luckperms/commands/CommandManager.java @@ -63,6 +63,7 @@ public class CommandManager { .add(new InfoCommand()) .add(new DebugCommand()) .add(new ImportCommand()) + // .add(new MigrationMainCommand()) TODO .add(new CreateGroup()) .add(new DeleteGroup()) .add(new ListGroups()) diff --git a/common/src/main/java/me/lucko/luckperms/commands/MainCommand.java b/common/src/main/java/me/lucko/luckperms/commands/MainCommand.java index 885f852da..0cf202dee 100644 --- a/common/src/main/java/me/lucko/luckperms/commands/MainCommand.java +++ b/common/src/main/java/me/lucko/luckperms/commands/MainCommand.java @@ -76,7 +76,7 @@ public abstract class MainCommand { return CommandResult.INVALID_ARGS; } - Optional> o = subCommands.stream() + Optional> o = getSubCommands().stream() .filter(s -> s.getName().equalsIgnoreCase(args.get(requiredArgsLength - 1))) .limit(1) .findAny(); diff --git a/common/src/main/java/me/lucko/luckperms/commands/migration/MigrationMainCommand.java b/common/src/main/java/me/lucko/luckperms/commands/migration/MigrationMainCommand.java new file mode 100644 index 000000000..ef071c13f --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/migration/MigrationMainCommand.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016 Lucko (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. + */ + +package me.lucko.luckperms.commands.migration; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.commands.CommandResult; +import me.lucko.luckperms.commands.MainCommand; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.commands.migration.subcommands.MigrationPowerfulPerms; +import me.lucko.luckperms.constants.Constants; +import me.lucko.luckperms.constants.Message; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class MigrationMainCommand extends MainCommand { + private final List> subCommands = new ArrayList<>(); + + public MigrationMainCommand() { + super("Migration", "/%s migration", 1, null); + + try { + subCommands.add(new MigrationPowerfulPerms()); + } catch (Throwable ignored) { + } + + } + + @Override + public List> getSubCommands() { + return subCommands; + } + + @Override + protected boolean isAuthorized(Sender sender) { + return sender.getUuid().equals(Constants.getConsoleUUID()); + } + + @Override + protected CommandResult execute(LuckPermsPlugin plugin, Sender sender, List args, String label) { + if (!sender.getUuid().equals(Constants.getConsoleUUID())) { + Message.MIGRATION_NOT_CONSOLE.send(sender); + return CommandResult.NO_PERMISSION; + } + + return super.execute(plugin, sender, args, label); + } + + @Override + protected Object getTarget(String target, LuckPermsPlugin plugin, Sender sender) { + return new Object(); + } + + @Override + protected void cleanup(Object object, LuckPermsPlugin plugin) { + + } + + @Override + protected List getObjects(LuckPermsPlugin plugin) { + return Collections.emptyList(); + } + + @Override + protected List onTabComplete(Sender sender, List args, LuckPermsPlugin plugin) { + return Collections.emptyList(); + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationGroupManager.java b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationGroupManager.java new file mode 100644 index 000000000..9bcc89289 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationGroupManager.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 Lucko (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. + */ + +package me.lucko.luckperms.commands.migration.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.api.Logger; +import me.lucko.luckperms.commands.CommandResult; +import me.lucko.luckperms.commands.Predicate; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.constants.Permission; +import org.anjocaido.groupmanager.GroupManager; + +import java.util.List; + +public class MigrationGroupManager extends SubCommand { + public MigrationGroupManager() { + super("groupmanager", "Migration from GroupManager", + "/%s migration groupmanager [world names]", Permission.MIGRATION, Predicate.alwaysFalse()); + } + + @Override + public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List args, String label) { + final Logger log = plugin.getLog(); + if (!plugin.isPluginLoaded("GroupManager")) { + log.severe("GroupManager Migration: Error -> GroupManager is not loaded."); + return CommandResult.STATE_ERROR; + } + + GroupManager gm = (GroupManager) plugin.getPlugin("GroupManager"); + + // Migrate all users. + log.info("GroupManager Migration: Starting user migration."); + + // gm.getWorldsHolder().getWorldData(). + // TODO + return null; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPermissionsEx.java b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPermissionsEx.java new file mode 100644 index 000000000..fa5cb44a2 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPermissionsEx.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2016 Lucko (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. + */ + +package me.lucko.luckperms.commands.migration.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.api.Logger; +import me.lucko.luckperms.commands.CommandResult; +import me.lucko.luckperms.commands.Predicate; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.constants.Permission; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.users.User; +import ru.tehkode.permissions.PermissionGroup; +import ru.tehkode.permissions.PermissionManager; +import ru.tehkode.permissions.PermissionUser; +import ru.tehkode.permissions.bukkit.PermissionsEx; + +import java.util.List; +import java.util.UUID; + +public class MigrationPermissionsEx extends SubCommand { + public MigrationPermissionsEx() { + super("permissionsex", "Migration from PermissionsEx", + "/%s migration permissionsex [world names]", Permission.MIGRATION, Predicate.alwaysFalse()); + } + + @SuppressWarnings("deprecation") + @Override + public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List args, String label) { + final Logger log = plugin.getLog(); + if (!plugin.isPluginLoaded("PermissionsEx")) { + log.severe("PermissionsEx Migration: Error -> PermissionsEx is not loaded."); + return CommandResult.STATE_ERROR; + } + + PermissionsEx pex = (PermissionsEx) plugin.getPlugin("PermissionsEx"); + PermissionManager manager = null; // TODO + + // Migrate all users + log.info("PermissionsEx Migration: Starting user migration."); + for (PermissionUser user : manager.getUsers()) { + UUID u = UUID.fromString(user.getIdentifier()); + plugin.getDatastore().loadOrCreateUser(u, "null"); + User lpUser = plugin.getUserManager().get(u); + + try { + for (String node : user.getOwnPermissions(null)) { + boolean value = true; + if (node.startsWith("!")) { + node = node.substring(1); + value = false; + } + + try { + lpUser.setPermission(node, value); + } catch (ObjectAlreadyHasException ignored) {} + } + } catch (NullPointerException ignored) { + // Probably won't happen. I have no API docs on getOwnPermissions#null though. + } + + if (args != null && !args.isEmpty()) { + for (String world : args) { + for (String node : user.getOwnPermissions(world)) { + boolean value = true; + if (node.startsWith("!")) { + node = node.substring(1); + value = false; + } + + try { + lpUser.setPermission(node, value, "global", world); + } catch (ObjectAlreadyHasException ignored) {} + } + } + } + + for (String s : user.getGroupNames()) { + try { + lpUser.setPermission("group." + s.toLowerCase(), true); + } catch (ObjectAlreadyHasException ignored) {} + } + + if (args != null && !args.isEmpty()) { + for (String world : args) { + for (String s : user.getGroupNames(world)) { + try { + lpUser.setPermission("group." + s.toLowerCase(), true, "global", world); + } catch (ObjectAlreadyHasException ignored) {} + } + } + } + + plugin.getUserManager().cleanup(lpUser); + plugin.getDatastore().saveUser(lpUser); + } + + // Migrate all groups. + log.info("PermissionsEx Migration: Starting group migration."); + for (PermissionGroup group : manager.getGroupList()) { + final String name = group.getName().toLowerCase(); + plugin.getDatastore().createAndLoadGroup(name); + Group lpGroup = plugin.getGroupManager().get(name); + + try { + for (String node : group.getOwnPermissions(null)) { + boolean value = true; + if (node.startsWith("!")) { + node = node.substring(1); + value = false; + } + + try { + lpGroup.setPermission(node, value); + } catch (ObjectAlreadyHasException ignored) {} + } + } catch (NullPointerException ignored) { + // Probably won't happen. I have no API docs on getOwnPermissions#null though. + } + + if (args != null && !args.isEmpty()) { + for (String world : args) { + for (String node : group.getOwnPermissions(world)) { + boolean value = true; + if (node.startsWith("!")) { + node = node.substring(1); + value = false; + } + + try { + lpGroup.setPermission(node, value, "global", world); + } catch (ObjectAlreadyHasException ignored) {} + } + } + } + + for (PermissionGroup g : group.getParents()) { + try { + lpGroup.setPermission("group." + g.getName().toLowerCase(), true); + } catch (ObjectAlreadyHasException ignored) {} + } + + if (args != null && !args.isEmpty()) { + for (String world : args) { + for (PermissionGroup g : group.getParents(world)) { + try { + lpGroup.setPermission("group." + g.getName().toLowerCase(), true, "global", world); + } catch (ObjectAlreadyHasException ignored) {} + } + } + } + } + + return CommandResult.SUCCESS; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPowerfulPerms.java b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPowerfulPerms.java new file mode 100644 index 000000000..e8db26c20 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPowerfulPerms.java @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2016 Lucko (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. + */ + +package me.lucko.luckperms.commands.migration.subcommands; + +import com.github.cheesesoftware.PowerfulPermsAPI.*; +import com.zaxxer.hikari.HikariDataSource; +import lombok.Cleanup; +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.api.Logger; +import me.lucko.luckperms.commands.CommandResult; +import me.lucko.luckperms.commands.Predicate; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.core.PermissionHolder; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.users.User; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.*; +import java.util.concurrent.CountDownLatch; + +import static me.lucko.luckperms.constants.Permission.MIGRATION; + +public class MigrationPowerfulPerms extends SubCommand { + /* + What kind of API requires reflection to function with multiple versions... + Doesn't that just defeat the whole god damn point of having an API in the first place? + Whatever happened to the concept of depreciation and responsible API creation? + I tried to keep reflection to a minimum, but in some places there's no other option. + This class is a complete fucking mess for that reason. I sad now :( + */ + private static Method getPlayerGroupsMethod = null; + private static Method getGroupMethod = null; + private static boolean legacy = true; + + static { + try { + getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerOwnGroups", UUID.class, ResultRunnable.class); + getPlayerGroupsMethod.setAccessible(true); + } catch (NoSuchMethodException e) { + try { + getPlayerGroupsMethod = PermissionManager.class.getMethod("getPlayerGroups", UUID.class, ResultRunnable.class); + getPlayerGroupsMethod.setAccessible(true); + } catch (NoSuchMethodException e1) { + e1.printStackTrace(); + } + } + + try { + getGroupMethod = CachedGroup.class.getMethod("getGroup"); + getGroupMethod.setAccessible(true); + legacy = true; + } catch (NoSuchMethodException ignored) { + } + } + + + public MigrationPowerfulPerms() { + super("powerfulperms", "Migration from PowerfulPerms", + "/%s migration powerfulperms
", MIGRATION, Predicate.not(5)); + } + + @Override + public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List args, String label) { + try { + return run(plugin, args); + } catch (Throwable t) { + t.printStackTrace(); + return CommandResult.FAILURE; + } + } + + private CommandResult run(LuckPermsPlugin plugin, List args) { + final Logger log = plugin.getLog(); + if (!plugin.isPluginLoaded("PowerfulPerms")) { + log.severe("PowerfulPerms Migration: Error -> PowerfulPerms is not loaded."); + return CommandResult.STATE_ERROR; + } + + final String address = args.get(0); + final String database = args.get(1); + final String username = args.get(2); + final String password = args.get(3); + final String dbTable = args.get(4); + + // Find a list of UUIDs + log.info("PowerfulPerms Migration: Getting a list of UUIDs to migrate."); + + HikariDataSource hikari = new HikariDataSource(); + hikari.setMaximumPoolSize(2); + 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); + + Set uuids = new HashSet<>(); + + try { + @Cleanup Connection connection = hikari.getConnection(); + DatabaseMetaData meta = connection.getMetaData(); + + @Cleanup ResultSet tables = meta.getTables(null, null, dbTable, null); + if (!tables.next()) { + log.severe("PowerfulPerms Migration: Error - Couldn't find table."); + return CommandResult.FAILURE; + + } else { + @Cleanup PreparedStatement preparedStatement = connection.prepareStatement("SELECT `uuid` FROM " + dbTable); + ResultSet resultSet = preparedStatement.executeQuery(); + + while (resultSet.next()) { + uuids.add(UUID.fromString(resultSet.getString("uuid"))); + } + } + + } catch (Exception e) { + e.printStackTrace(); + return CommandResult.FAILURE; + } + + if (uuids.isEmpty()) { + log.severe("PowerfulPerms Migration: Error - Unable to find any UUIDs to migrate."); + return CommandResult.FAILURE; + } + + log.info("PowerfulPerms Migration: Found " + uuids.size() + " uuids. Starting migration."); + + PowerfulPermsPlugin ppPlugin = (PowerfulPermsPlugin) plugin.getPlugin("PowerfulPerms"); + PermissionManager pm = ppPlugin.getPermissionManager(); + + final Map progress = new HashMap<>(); + + // Migrate all users and their groups + for (UUID uuid : uuids) { + progress.put(uuid, new CountDownLatch(2)); + + // Create a LuckPerms user for the UUID + plugin.getDatastore().loadOrCreateUser(uuid, "null"); + User user = plugin.getUserManager().get(uuid); + + // Get a list of Permissions held by the user from the PP API. + pm.getPlayerOwnPermissions(uuid, new LPResultRunnable>() { + @Override + public void run() { + List perms = this.getResult(); + perms.forEach(p -> applyPerm(user, p)); + + // Update the progress so the user can be saved and unloaded. + synchronized (progress) { + progress.get(uuid).countDown(); + if (progress.get(uuid).getCount() == 0) { + plugin.getDatastore().saveUser(user); + plugin.getUserManager().cleanup(user); + } + } + + } + }); + + // Migrate the user's groups to LuckPerms from PP. + try { + getPlayerGroupsMethod.invoke(pm, uuid, new LPResultRunnable>>() { + @Override + public void run() { + Map> groups = getResult(); + + for (Map.Entry> e : groups.entrySet()) { + final String server; + if (e.getKey() != null && (e.getKey().equals("") || e.getKey().equalsIgnoreCase("all"))) { + server = null; + } else { + server = e.getKey(); + } + + // This is horrible. So many random API changes through versions, no depreciation. + if (legacy) { + e.getValue().stream() + .filter(cg -> !cg.isNegated()) + .map(cg -> { + try { + return (Group) getGroupMethod.invoke(cg); + } catch (IllegalAccessException | InvocationTargetException e1) { + e1.printStackTrace(); + return null; + } + }) + .forEach(g -> { + if (g != null) { + if (server == null) { + try { + user.setPermission("group." + g.getName().toLowerCase(), true); + } catch (ObjectAlreadyHasException ignored) {} + } else { + try { + user.setPermission("group." + g.getName().toLowerCase(), true, server); + } catch (ObjectAlreadyHasException ignored) {} + } + } + }); + } else { + e.getValue().stream() + .filter(g -> !g.hasExpired() && !g.isNegated()) + .forEach(g -> { + final Group group = pm.getGroup(g.getGroupId()); + if (g.willExpire()) { + if (server == null) { + try { + user.setPermission("group." + group.getName().toLowerCase(), true, g.getExpirationDate().getTime() / 1000L); + } catch (ObjectAlreadyHasException ignored) {} + } else { + try { + user.setPermission("group." + group.getName().toLowerCase(), true, server, g.getExpirationDate().getTime() / 1000L); + } catch (ObjectAlreadyHasException ignored) {} + } + + } else { + if (server == null) { + try { + user.setPermission("group." + group.getName().toLowerCase(), true); + } catch (ObjectAlreadyHasException ignored) {} + } else { + try { + user.setPermission("group." + group.getName().toLowerCase(), true, server); + } catch (ObjectAlreadyHasException ignored) {} + } + } + }); + } + } + + // Update the progress so the user can be saved and unloaded. + synchronized (progress) { + progress.get(uuid).countDown(); + if (progress.get(uuid).getCount() == 0) { + plugin.getDatastore().saveUser(user); + plugin.getUserManager().cleanup(user); + } + } + } + }); + } catch (IllegalAccessException | InvocationTargetException e) { + log.info("PowerfulPerms Migration: Error"); + e.printStackTrace(); + } + } + + // The user processes will run individually in separate threads. + // In the meantime, it's should be safe to load in the groups on this thread. + log.info("PowerfulPerms Migration: User migration is now running. Starting group migration."); + + // Let's import groups. yay + Map groups = pm.getGroups(); + for (Group g : groups.values()) { + plugin.getDatastore().createAndLoadGroup(g.getName().toLowerCase()); + final me.lucko.luckperms.groups.Group group = plugin.getGroupManager().get(g.getName().toLowerCase()); + + for (Permission p : g.getOwnPermissions()) { + applyPerm(group, p); + } + + for (Group parent : g.getParents()) { + try { + group.setPermission("group." + parent.getName().toLowerCase(), true); + } catch (ObjectAlreadyHasException ignored) {} + } + + plugin.getDatastore().saveGroup(group); + } + + // All groups are now migrated, but there may still be some users being migrated. + // This block will wait for all users to be completed. + log.info("PowerfulPerms Migration: All groups are now migrated. Waiting for user migration to complete."); + log.info("PowerfulPerms Migration: This may take some time."); + boolean sleep = true; + while (sleep) { + sleep = false; + + for (Map.Entry e : progress.entrySet()) { + if (e.getValue().getCount() != 0) { + sleep = true; + break; + } + } + + if (sleep) { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + + // We done. + log.info("PowerfulPerms Migration: Success! Migration completed without any errors."); + return CommandResult.SUCCESS; + } + + private void applyPerm(PermissionHolder holder, Permission p) { + String node = p.getPermissionString(); + boolean value = true; + if (node.startsWith("!")) { + node = node.substring(1); + value = false; + } + + String server = p.getServer(); + if (server != null && server.equalsIgnoreCase("all")) { + server = null; + } + + String world = p.getWorld(); + if (world != null && world.equalsIgnoreCase("all")) { + world = null; + } + + long expireAt = 0L; + if (!legacy) { + if (p.willExpire()) { + expireAt = p.getExpirationDate().getTime() / 1000L; + } + } + + if (world != null && server == null) { + server = "global"; + } + + if (world != null) { + if (expireAt == 0L) { + try { + holder.setPermission(node, value, server, world); + } catch (ObjectAlreadyHasException e) { + e.printStackTrace(); + } + } else { + try { + holder.setPermission(node, value, server, world, expireAt); + } catch (ObjectAlreadyHasException e) { + e.printStackTrace(); + } + } + + } else if (server != null) { + if (expireAt == 0L) { + try { + holder.setPermission(node, value, server); + } catch (ObjectAlreadyHasException ignored) {} + } else { + try { + holder.setPermission(node, value, server, expireAt); + } catch (ObjectAlreadyHasException ignored) {} + } + } else { + if (expireAt == 0L) { + try { + holder.setPermission(node, value); + } catch (ObjectAlreadyHasException ignored) {} + } else { + try { + holder.setPermission(node, value, expireAt); + } catch (ObjectAlreadyHasException ignored) {} + } + } + } + + /** + * Overrides the default ResultRunnable, callbacks will always run in the same thread. (an async one, hopefully.) + * @param type + */ + @SuppressWarnings("WeakerAccess") + public abstract class LPResultRunnable extends ResultRunnable { + + public LPResultRunnable() { + super(); + super.sameThread = true; + } + + public T getResult() { + return super.result; + } + + } +} diff --git a/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationZPermissions.java b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationZPermissions.java new file mode 100644 index 000000000..9a8e00ae7 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationZPermissions.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016 Lucko (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. + */ + +package me.lucko.luckperms.commands.migration.subcommands; + +import me.lucko.luckperms.LuckPermsPlugin; +import me.lucko.luckperms.api.Logger; +import me.lucko.luckperms.commands.CommandResult; +import me.lucko.luckperms.commands.Predicate; +import me.lucko.luckperms.commands.Sender; +import me.lucko.luckperms.commands.SubCommand; +import me.lucko.luckperms.constants.Permission; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.tracks.Track; +import me.lucko.luckperms.users.User; +import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * <3 <3 zPermissions <3 <3 + * Finally a permissions plugin with a decent API. *sigh* + */ +public class MigrationZPermissions extends SubCommand { + public MigrationZPermissions() { + super("zpermissions", "Migration from zPermissions", + "/%s migration zpermissions [world names]", Permission.MIGRATION, Predicate.alwaysFalse()); + } + + @Override + public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Object o, List args, String label) { + final Logger log = plugin.getLog(); + if (!plugin.isPluginLoaded("zPermissions")) { + log.severe("zPermissions Migration: Error -> zPermissions is not loaded."); + return CommandResult.STATE_ERROR; + } + + ZPermissionsService service = (ZPermissionsService) plugin.getService(ZPermissionsService.class); + if (service == null) { + log.severe("zPermissions Migration: Error -> zPermissions is not loaded."); + return CommandResult.STATE_ERROR; + } + + // Migrate all users. + log.info("zPermissions Migration: Starting user migration."); + for (UUID u : service.getAllPlayersUUID()) { + plugin.getDatastore().loadOrCreateUser(u, "null"); + User user = plugin.getUserManager().get(u); + + for (Map.Entry e : service.getPlayerPermissions(null, null, u).entrySet()) { + try { + user.setPermission(e.getKey(), e.getValue()); + } catch (ObjectAlreadyHasException ignored) {} + } + + if (args != null && !args.isEmpty()) { + for (String world : args) { + for (Map.Entry e : service.getPlayerPermissions(world, null, u).entrySet()) { + try { + user.setPermission(e.getKey(), e.getValue(), "global", world); + } catch (ObjectAlreadyHasException ignored) {} + } + } + } + + for (String g : service.getPlayerAssignedGroups(u)) { + try { + user.setPermission("group." + g.toLowerCase(), true); + } catch (ObjectAlreadyHasException ignored) {} + } + + user.setPrimaryGroup(service.getPlayerPrimaryGroup(u)); + plugin.getUserManager().cleanup(user); + plugin.getDatastore().saveUser(user); + } + + // Migrate all tracks + log.info("zPermissions Migration: Starting track migration."); + for (String t : service.getAllTracks()) { + plugin.getDatastore().createAndLoadTrack(t.toLowerCase()); + Track track = plugin.getTrackManager().get(t.toLowerCase()); + + track.setGroups(service.getTrackGroups(t)); + + plugin.getDatastore().saveTrack(track); + } + + // Migrate all groups + log.info("zPermissions Migration: Starting group migration."); + for (String g : service.getAllGroups()) { + plugin.getDatastore().createAndLoadGroup(g.toLowerCase()); + Group group = plugin.getGroupManager().get(g.toLowerCase()); + + for (Map.Entry e : service.getGroupPermissions(null, null, g).entrySet()) { + try { + group.setPermission(e.getKey(), e.getValue()); + } catch (ObjectAlreadyHasException ignored) {} + } + + if (args != null && !args.isEmpty()) { + for (String world : args) { + for (Map.Entry e : service.getGroupPermissions(world, null, g).entrySet()) { + try { + group.setPermission(e.getKey(), e.getValue(), "global", world); + } catch (ObjectAlreadyHasException ignored) {} + } + } + } + + plugin.getDatastore().saveGroup(group); + } + + log.info("zPermissions Migration: Complete!"); + return CommandResult.SUCCESS; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/constants/Message.java b/common/src/main/java/me/lucko/luckperms/constants/Message.java index 75bcda0ff..3d3c0a9fc 100644 --- a/common/src/main/java/me/lucko/luckperms/constants/Message.java +++ b/common/src/main/java/me/lucko/luckperms/constants/Message.java @@ -298,7 +298,9 @@ public enum Message { ), IMPORT_END_ERROR_CONTENT("&e(Import) &d-> &c%s", true), - IMPORT_END_ERROR_FOOTER("&e(Import) &7<------------------------------------------>", true); + IMPORT_END_ERROR_FOOTER("&e(Import) &7<------------------------------------------>", true), + + MIGRATION_NOT_CONSOLE("Migration must be performed from the Console.", true); private String message; private boolean showPrefix; diff --git a/common/src/main/java/me/lucko/luckperms/constants/Permission.java b/common/src/main/java/me/lucko/luckperms/constants/Permission.java index 6921476fe..491ef9880 100644 --- a/common/src/main/java/me/lucko/luckperms/constants/Permission.java +++ b/common/src/main/java/me/lucko/luckperms/constants/Permission.java @@ -89,7 +89,9 @@ public enum Permission { LOG_TRACK_HISTORY("trackhistory", "log"), LOG_SEARCH("search", "log"), LOG_NOTIFY("notify", "log"), - LOG_EXPORT("export", "log"); + LOG_EXPORT("export", "log"), + + MIGRATION("migration", null); private String node; private String group; diff --git a/pom.xml b/pom.xml index bdf02ba52..2b45b66e8 100644 --- a/pom.xml +++ b/pom.xml @@ -71,5 +71,13 @@ sponge-repo https://repo.spongepowered.org/maven + + pex-repo + http://pex-repo.aoeu.xyz + + + alskebo-repo + http://repo.alskebo.com/repository/maven-releases + diff --git a/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java index edf168f31..acd90a9a2 100644 --- a/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java @@ -190,6 +190,11 @@ public class LPSpongePlugin implements LuckPermsPlugin { return "null"; } + @Override + public Type getType() { + return Type.SPONGE; + } + @Override public Message getPlayerStatus(UUID uuid) { return game.getServer().getPlayer(getUuidCache().getExternalUUID(uuid)).isPresent() ? Message.PLAYER_ONLINE : Message.PLAYER_OFFLINE; @@ -224,6 +229,21 @@ public class LPSpongePlugin implements LuckPermsPlugin { return p.get().getDescriptions().stream().map(PermissionDescription::getId).collect(Collectors.toList()); } + @Override + public Object getPlugin(String name) { + return game.getPluginManager().getPlugin(name).get().getInstance().get(); + } + + @Override + public Object getService(Class clazz) { + return Sponge.getServiceManager().provideUnchecked(clazz); + } + + @Override + public boolean isPluginLoaded(String name) { + return game.getPluginManager().isLoaded(name); + } + @Override public void runUpdateTask() { scheduler.createTaskBuilder().async().execute(new UpdateTask(this)).submit(LPSpongePlugin.this);