diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java index 7ffbe7784..4d6732cfe 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java @@ -33,9 +33,11 @@ import me.lucko.luckperms.common.core.model.Track; import me.lucko.luckperms.common.core.model.User; import me.lucko.luckperms.common.data.Log; import me.lucko.luckperms.common.storage.backing.AbstractBacking; +import me.lucko.luckperms.common.storage.holder.HeldPermission; import me.lucko.luckperms.common.storage.wrappings.BufferedOutputStorage; import me.lucko.luckperms.common.storage.wrappings.TolerantStorage; +import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -94,6 +96,11 @@ public class AbstractStorage implements Storage { return makeFuture(backing::getUniqueUsers); } + @Override + public CompletableFuture>> getUsersWithPermission(String permission) { + return makeFuture(() -> backing.getUsersWithPermission(permission)); + } + @Override public CompletableFuture createAndLoadGroup(String name) { return makeFuture(() -> backing.createAndLoadGroup(name)); @@ -119,6 +126,11 @@ public class AbstractStorage implements Storage { return makeFuture(() -> backing.deleteGroup(group)); } + @Override + public CompletableFuture>> getGroupsWithPermission(String permission) { + return makeFuture(() -> backing.getGroupsWithPermission(permission)); + } + @Override public CompletableFuture createAndLoadTrack(String name) { return makeFuture(() -> backing.createAndLoadTrack(name)); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/SplitBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/SplitBacking.java index 165db75c0..d03da11a9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/SplitBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/SplitBacking.java @@ -31,7 +31,9 @@ import me.lucko.luckperms.common.core.model.Track; import me.lucko.luckperms.common.core.model.User; import me.lucko.luckperms.common.data.Log; import me.lucko.luckperms.common.storage.backing.AbstractBacking; +import me.lucko.luckperms.common.storage.holder.HeldPermission; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -94,6 +96,11 @@ public class SplitBacking extends AbstractBacking { return backing.get(types.get("user")).getUniqueUsers(); } + @Override + public List> getUsersWithPermission(String permission) { + return backing.get(types.get("user")).getUsersWithPermission(permission); + } + @Override public boolean createAndLoadGroup(String name) { return backing.get(types.get("group")).createAndLoadGroup(name); @@ -119,6 +126,11 @@ public class SplitBacking extends AbstractBacking { return backing.get(types.get("group")).deleteGroup(group); } + @Override + public List> getGroupsWithPermission(String permission) { + return backing.get(types.get("group")).getGroupsWithPermission(permission); + } + @Override public boolean createAndLoadTrack(String name) { return backing.get(types.get("track")).createAndLoadTrack(name); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java index b4f87c1c1..f636e80a2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java @@ -27,7 +27,9 @@ import me.lucko.luckperms.common.core.model.Group; import me.lucko.luckperms.common.core.model.Track; import me.lucko.luckperms.common.core.model.User; import me.lucko.luckperms.common.data.Log; +import me.lucko.luckperms.common.storage.holder.HeldPermission; +import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -61,6 +63,8 @@ public interface Storage { CompletableFuture> getUniqueUsers(); + CompletableFuture>> getUsersWithPermission(String permission); + CompletableFuture createAndLoadGroup(String name); CompletableFuture loadGroup(String name); @@ -71,6 +75,8 @@ public interface Storage { CompletableFuture deleteGroup(Group group); + CompletableFuture>> getGroupsWithPermission(String permission); + CompletableFuture createAndLoadTrack(String name); CompletableFuture loadTrack(String name); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/AbstractBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/AbstractBacking.java index 65f4237e0..d697cc758 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/AbstractBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/AbstractBacking.java @@ -33,7 +33,9 @@ import me.lucko.luckperms.common.core.model.Group; import me.lucko.luckperms.common.core.model.Track; import me.lucko.luckperms.common.core.model.User; import me.lucko.luckperms.common.data.Log; +import me.lucko.luckperms.common.storage.holder.HeldPermission; +import java.util.List; import java.util.Set; import java.util.UUID; @@ -66,6 +68,8 @@ public abstract class AbstractBacking { public abstract Set getUniqueUsers(); + public abstract List> getUsersWithPermission(String permission); + public abstract boolean createAndLoadGroup(String name); public abstract boolean loadGroup(String name); @@ -76,6 +80,8 @@ public abstract class AbstractBacking { public abstract boolean deleteGroup(Group group); + public abstract List> getGroupsWithPermission(String permission); + public abstract boolean createAndLoadTrack(String name); public abstract boolean loadTrack(String name); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java index 05839e86a..dbad3c574 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java @@ -22,10 +22,13 @@ package me.lucko.luckperms.common.storage.backing; +import com.google.common.collect.ImmutableList; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; +import me.lucko.luckperms.api.Node; import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.core.NodeFactory; import me.lucko.luckperms.common.core.UserIdentifier; import me.lucko.luckperms.common.core.model.Group; import me.lucko.luckperms.common.core.model.Track; @@ -33,6 +36,8 @@ import me.lucko.luckperms.common.core.model.User; import me.lucko.luckperms.common.managers.GroupManager; import me.lucko.luckperms.common.managers.TrackManager; import me.lucko.luckperms.common.managers.impl.GenericUserManager; +import me.lucko.luckperms.common.storage.holder.HeldPermission; +import me.lucko.luckperms.common.storage.holder.NodeHeldPermission; import me.lucko.luckperms.common.utils.ThrowingFunction; import java.io.BufferedReader; @@ -270,6 +275,51 @@ public class JSONBacking extends FlatfileBacking { .collect(Collectors.toSet()); } + @Override + public List> getUsersWithPermission(String permission) { + ImmutableList.Builder> held = ImmutableList.builder(); + boolean success = call(() -> { + File[] files = usersDir.listFiles((dir, name1) -> name1.endsWith(".json")); + if (files == null) return false; + + for (File file : files) { + UUID holder = UUID.fromString(file.getName().substring(0, file.getName().length() - 5)); + Map nodes = new HashMap<>(); + fileToReader(file, reader -> { + reader.beginObject(); + reader.nextName(); // uuid record + reader.nextString(); // uuid + reader.nextName(); // name record + reader.nextString(); // name + reader.nextName(); // primaryGroup record + reader.nextString(); // primaryGroup + reader.nextName(); //perms + reader.beginObject(); + while (reader.hasNext()) { + String node = reader.nextName(); + boolean b = reader.nextBoolean(); + nodes.put(node, b); + } + + reader.endObject(); + reader.endObject(); + return true; + }); + + for (Map.Entry e : nodes.entrySet()) { + Node node = NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()); + if (!node.getPermission().equalsIgnoreCase(permission)) { + continue; + } + + held.add(NodeHeldPermission.of(holder, node)); + } + } + return true; + }, false); + return success ? held.build() : null; + } + @Override public boolean createAndLoadGroup(String name) { Group group = plugin.getGroupManager().getOrMake(name); @@ -419,6 +469,47 @@ public class JSONBacking extends FlatfileBacking { } } + @Override + public List> getGroupsWithPermission(String permission) { + ImmutableList.Builder> held = ImmutableList.builder(); + boolean success = call(() -> { + File[] files = groupsDir.listFiles((dir, name1) -> name1.endsWith(".json")); + if (files == null) return false; + + for (File file : files) { + String holder = file.getName().substring(0, file.getName().length() - 5); + Map nodes = new HashMap<>(); + fileToReader(file, reader -> { + reader.beginObject(); + reader.nextName(); // name record + reader.nextString(); // name + reader.nextName(); // perms + reader.beginObject(); + while (reader.hasNext()) { + String node = reader.nextName(); + boolean b = reader.nextBoolean(); + nodes.put(node, b); + } + + reader.endObject(); + reader.endObject(); + return true; + }); + + for (Map.Entry e : nodes.entrySet()) { + Node node = NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()); + if (!node.getPermission().equalsIgnoreCase(permission)) { + continue; + } + + held.add(NodeHeldPermission.of(holder, node)); + } + } + return true; + }, false); + return success ? held.build() : null; + } + @Override public boolean createAndLoadTrack(String name) { Track track = plugin.getTrackManager().getOrMake(name); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java index 20cc7479a..ca1a3526f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.common.storage.backing; +import com.google.common.collect.ImmutableList; import com.mongodb.MongoClient; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; @@ -31,7 +32,9 @@ import com.mongodb.client.MongoDatabase; import com.mongodb.client.model.InsertOneOptions; import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.api.Node; import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.core.NodeFactory; import me.lucko.luckperms.common.core.UserIdentifier; import me.lucko.luckperms.common.core.model.Group; import me.lucko.luckperms.common.core.model.Track; @@ -41,6 +44,8 @@ import me.lucko.luckperms.common.managers.GroupManager; import me.lucko.luckperms.common.managers.TrackManager; import me.lucko.luckperms.common.managers.impl.GenericUserManager; import me.lucko.luckperms.common.storage.DatastoreConfiguration; +import me.lucko.luckperms.common.storage.holder.HeldPermission; +import me.lucko.luckperms.common.storage.holder.NodeHeldPermission; import org.bson.Document; @@ -52,6 +57,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.function.Function; import java.util.stream.Collectors; import static me.lucko.luckperms.common.core.model.PermissionHolder.exportToLegacy; @@ -71,14 +77,18 @@ public class MongoDBBacking extends AbstractBacking { /* MongoDB does not allow '.' or '$' in key names. See: https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names The following two methods convert the node maps so they can be stored. */ + + private static final Function CONVERT_STRING = s -> s.replace(".", "[**DOT**]").replace("$", "[**DOLLAR**]"); + private static final Function REVERT_STRING = s -> s.replace("[**DOT**]", ".").replace("[**DOLLAR**]", "$"); + private static Map convert(Map map) { return map.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().replace(".", "[**DOT**]").replace("$", "[**DOLLAR**]"), Map.Entry::getValue)); + .collect(Collectors.toMap(e -> CONVERT_STRING.apply(e.getKey()), Map.Entry::getValue)); } private static Map revert(Map map) { return map.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().replace("[**DOT**]", ".").replace("[**DOLLAR**]", "$"), Map.Entry::getValue)); + .collect(Collectors.toMap(e -> REVERT_STRING.apply(e.getKey()), Map.Entry::getValue)); } private static Document fromUser(User user) { @@ -315,6 +325,35 @@ public class MongoDBBacking extends AbstractBacking { return success ? uuids : null; } + @Override + public List> getUsersWithPermission(String permission) { + ImmutableList.Builder> held = ImmutableList.builder(); + boolean success = call(() -> { + MongoCollection c = database.getCollection("users"); + + try (MongoCursor cursor = c.find().iterator()) { + while (cursor.hasNext()) { + Document d = cursor.next(); + + UUID holder = UUID.fromString(d.getString("_id")); + Map perms = revert((Map) d.get("perms")); + + for (Map.Entry e : perms.entrySet()) { + Node node = NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()); + if (!node.getPermission().equalsIgnoreCase(permission)) { + continue; + } + + held.add(NodeHeldPermission.of(holder, node)); + } + } + } + return true; + }, false); + + return success ? held.build() : null; + } + @Override public boolean createAndLoadGroup(String name) { Group group = plugin.getGroupManager().getOrMake(name); @@ -419,6 +458,35 @@ public class MongoDBBacking extends AbstractBacking { return success; } + @Override + public List> getGroupsWithPermission(String permission) { + ImmutableList.Builder> held = ImmutableList.builder(); + boolean success = call(() -> { + MongoCollection c = database.getCollection("groups"); + + try (MongoCursor cursor = c.find().iterator()) { + while (cursor.hasNext()) { + Document d = cursor.next(); + + String holder = d.getString("_id"); + Map perms = revert((Map) d.get("perms")); + + for (Map.Entry e : perms.entrySet()) { + Node node = NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()); + if (!node.getPermission().equalsIgnoreCase(permission)) { + continue; + } + + held.add(NodeHeldPermission.of(holder, node)); + } + } + } + return true; + }, false); + + return success ? held.build() : null; + } + @Override public boolean createAndLoadTrack(String name) { Track track = plugin.getTrackManager().getOrMake(name); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java index b01f08926..cc1e536dd 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java @@ -24,6 +24,7 @@ package me.lucko.luckperms.common.storage.backing; import lombok.Getter; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -42,6 +43,8 @@ import me.lucko.luckperms.common.managers.impl.GenericUserManager; import me.lucko.luckperms.common.storage.backing.sqlprovider.SQLProvider; import me.lucko.luckperms.common.storage.backing.utils.LegacySchemaMigration; import me.lucko.luckperms.common.storage.backing.utils.NodeDataHolder; +import me.lucko.luckperms.common.storage.holder.HeldPermission; +import me.lucko.luckperms.common.storage.holder.NodeHeldPermission; import java.io.BufferedReader; import java.io.InputStream; @@ -72,6 +75,7 @@ public class SQLBacking extends AbstractBacking { private static final String USER_PERMISSIONS_DELETE = "DELETE FROM {prefix}user_permissions WHERE uuid=?"; private static final String USER_PERMISSIONS_INSERT = "INSERT INTO {prefix}user_permissions(uuid, permission, value, server, world, expiry, contexts) VALUES(?, ?, ?, ?, ?, ?, ?)"; private static final String USER_PERMISSIONS_SELECT_DISTINCT = "SELECT DISTINCT uuid FROM {prefix}user_permissions"; + private static final String USER_PERMISSIONS_SELECT_PERMISSION = "SELECT uuid, value, server, world, expiry, contexts FROM {prefix}user_permissions WHERE permission=?"; private static final String PLAYER_SELECT = "SELECT username, primary_group FROM {prefix}players WHERE uuid=?"; private static final String PLAYER_SELECT_UUID = "SELECT uuid FROM {prefix}players WHERE username=? LIMIT 1"; @@ -85,6 +89,7 @@ public class SQLBacking extends AbstractBacking { private static final String GROUP_PERMISSIONS_DELETE = "DELETE FROM {prefix}group_permissions WHERE name=?"; private static final String GROUP_PERMISSIONS_DELETE_SPECIFIC = "DELETE FROM {prefix}group_permissions WHERE name=? AND permission=? AND value=? AND server=? AND world=? AND expiry=? AND contexts=?"; private static final String GROUP_PERMISSIONS_INSERT = "INSERT INTO {prefix}group_permissions(name, permission, value, server, world, expiry, contexts) VALUES(?, ?, ?, ?, ?, ?, ?)"; + private static final String GROUP_PERMISSIONS_SELECT_PERMISSION = "SELECT name, value, server, world, expiry, contexts FROM {prefix}group_permissions WHERE permission=?"; private static final String GROUP_SELECT_ALL = "SELECT name FROM {prefix}groups"; private static final String GROUP_INSERT = "INSERT INTO {prefix}groups VALUES(?)"; @@ -404,7 +409,7 @@ public class SQLBacking extends AbstractBacking { ps.setString(4, nd.getServer()); ps.setString(5, nd.getWorld()); ps.setLong(6, nd.getExpiry()); - ps.setString(7, nd.getContexts()); + ps.setString(7, nd.serialiseContext()); ps.addBatch(); } ps.executeBatch(); @@ -425,7 +430,7 @@ public class SQLBacking extends AbstractBacking { ps.setString(4, nd.getServer()); ps.setString(5, nd.getWorld()); ps.setLong(6, nd.getExpiry()); - ps.setString(7, nd.getContexts()); + ps.setString(7, nd.serialiseContext()); ps.addBatch(); } ps.executeBatch(); @@ -509,6 +514,33 @@ public class SQLBacking extends AbstractBacking { return uuids; } + @Override + public List> getUsersWithPermission(String permission) { + ImmutableList.Builder> held = ImmutableList.builder(); + try (Connection c = provider.getConnection()) { + try (PreparedStatement ps = c.prepareStatement(prefix.apply(USER_PERMISSIONS_SELECT_PERMISSION))) { + ps.setString(1, permission); + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + UUID holder = UUID.fromString(rs.getString("uuid")); + boolean value = rs.getBoolean("value"); + String server = rs.getString("server"); + String world = rs.getString("world"); + long expiry = rs.getLong("expiry"); + String contexts = rs.getString("contexts"); + + NodeDataHolder data = NodeDataHolder.of(permission, value, server, world, expiry, contexts); + held.add(NodeHeldPermission.of(holder, data)); + } + } + } + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + return held.build(); + } + @Override public boolean createAndLoadGroup(String name) { List groups = new ArrayList<>(); @@ -692,7 +724,7 @@ public class SQLBacking extends AbstractBacking { ps.setString(4, nd.getServer()); ps.setString(5, nd.getWorld()); ps.setLong(6, nd.getExpiry()); - ps.setString(7, nd.getContexts()); + ps.setString(7, nd.serialiseContext()); ps.addBatch(); } ps.executeBatch(); @@ -713,7 +745,7 @@ public class SQLBacking extends AbstractBacking { ps.setString(4, nd.getServer()); ps.setString(5, nd.getWorld()); ps.setLong(6, nd.getExpiry()); - ps.setString(7, nd.getContexts()); + ps.setString(7, nd.serialiseContext()); ps.addBatch(); } ps.executeBatch(); @@ -756,6 +788,33 @@ public class SQLBacking extends AbstractBacking { } } + @Override + public List> getGroupsWithPermission(String permission) { + ImmutableList.Builder> held = ImmutableList.builder(); + try (Connection c = provider.getConnection()) { + try (PreparedStatement ps = c.prepareStatement(prefix.apply(GROUP_PERMISSIONS_SELECT_PERMISSION))) { + ps.setString(1, permission); + try (ResultSet rs = ps.executeQuery()) { + while (rs.next()) { + String holder = rs.getString("name"); + boolean value = rs.getBoolean("value"); + String server = rs.getString("server"); + String world = rs.getString("world"); + long expiry = rs.getLong("expiry"); + String contexts = rs.getString("contexts"); + + NodeDataHolder data = NodeDataHolder.of(permission, value, server, world, expiry, contexts); + held.add(NodeHeldPermission.of(holder, data)); + } + } + } + } catch (SQLException e) { + e.printStackTrace(); + return null; + } + return held.build(); + } + @Override public boolean createAndLoadTrack(String name) { Track track = plugin.getTrackManager().getOrMake(name); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java index 119276952..f02250032 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java @@ -22,7 +22,11 @@ package me.lucko.luckperms.common.storage.backing; +import com.google.common.collect.ImmutableList; + +import me.lucko.luckperms.api.Node; import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.core.NodeFactory; import me.lucko.luckperms.common.core.UserIdentifier; import me.lucko.luckperms.common.core.model.Group; import me.lucko.luckperms.common.core.model.Track; @@ -30,6 +34,8 @@ import me.lucko.luckperms.common.core.model.User; import me.lucko.luckperms.common.managers.GroupManager; import me.lucko.luckperms.common.managers.TrackManager; import me.lucko.luckperms.common.managers.impl.GenericUserManager; +import me.lucko.luckperms.common.storage.holder.HeldPermission; +import me.lucko.luckperms.common.storage.holder.NodeHeldPermission; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; @@ -226,6 +232,36 @@ public class YAMLBacking extends FlatfileBacking { .collect(Collectors.toSet()); } + @Override + public List> getUsersWithPermission(String permission) { + ImmutableList.Builder> held = ImmutableList.builder(); + boolean success = call(() -> { + File[] files = usersDir.listFiles((dir, name1) -> name1.endsWith(".yml")); + if (files == null) return false; + + for (File file : files) { + UUID holder = UUID.fromString(file.getName().substring(0, file.getName().length() - 4)); + Map nodes = new HashMap<>(); + readMapFromFile(file, values -> { + Map perms = (Map) values.get("perms"); + nodes.putAll(perms); + return true; + }); + + for (Map.Entry e : nodes.entrySet()) { + Node node = NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()); + if (!node.getPermission().equalsIgnoreCase(permission)) { + continue; + } + + held.add(NodeHeldPermission.of(holder, node)); + } + } + return true; + }, false); + return success ? held.build() : null; + } + @Override public boolean createAndLoadGroup(String name) { Group group = plugin.getGroupManager().getOrMake(name); @@ -335,6 +371,36 @@ public class YAMLBacking extends FlatfileBacking { } } + @Override + public List> getGroupsWithPermission(String permission) { + ImmutableList.Builder> held = ImmutableList.builder(); + boolean success = call(() -> { + File[] files = groupsDir.listFiles((dir, name1) -> name1.endsWith(".yml")); + if (files == null) return false; + + for (File file : files) { + String holder = file.getName().substring(0, file.getName().length() - 4); + Map nodes = new HashMap<>(); + readMapFromFile(file, values -> { + Map perms = (Map) values.get("perms"); + nodes.putAll(perms); + return true; + }); + + for (Map.Entry e : nodes.entrySet()) { + Node node = NodeFactory.fromSerialisedNode(e.getKey(), e.getValue()); + if (!node.getPermission().equalsIgnoreCase(permission)) { + continue; + } + + held.add(NodeHeldPermission.of(holder, node)); + } + } + return true; + }, false); + return success ? held.build() : null; + } + @Override public boolean createAndLoadTrack(String name) { Track track = plugin.getTrackManager().getOrMake(name); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/utils/LegacySchemaMigration.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/utils/LegacySchemaMigration.java index 76a283d06..06bf13776 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/utils/LegacySchemaMigration.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/utils/LegacySchemaMigration.java @@ -161,7 +161,7 @@ public class LegacySchemaMigration implements Runnable { ps.setString(4, nd.getServer()); ps.setString(5, nd.getWorld()); ps.setLong(6, nd.getExpiry()); - ps.setString(7, nd.getContexts()); + ps.setString(7, nd.serialiseContext()); ps.addBatch(); } ps.executeBatch(); @@ -240,7 +240,7 @@ public class LegacySchemaMigration implements Runnable { ps.setString(4, nd.getServer()); ps.setString(5, nd.getWorld()); ps.setLong(6, nd.getExpiry()); - ps.setString(7, nd.getContexts()); + ps.setString(7, nd.serialiseContext()); ps.addBatch(); } ps.executeBatch(); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/utils/NodeDataHolder.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/utils/NodeDataHolder.java index 9a53edd65..24f93d14f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/utils/NodeDataHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/utils/NodeDataHolder.java @@ -27,6 +27,8 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -52,16 +54,30 @@ public class NodeDataHolder { node.getServer().orElse("global"), node.getWorld().orElse("global"), node.isTemporary() ? node.getExpiryUnixTime() : 0L, - GSON.toJson(node.getContexts().toMultimap().asMap()) + node.getContexts().toMultimap() ); } + public static NodeDataHolder of(String permission, boolean value, String server, String world, long expiry, String contexts) { + Map> deserializedContexts = GSON.fromJson(contexts, CONTEXT_TYPE); + Multimap map = HashMultimap.create(); + for (Map.Entry> e : deserializedContexts.entrySet()) { + map.putAll(e.getKey(), e.getValue()); + } + + return new NodeDataHolder(permission, value, server, world, expiry, map); + } + private final String permission; private final boolean value; private final String server; private final String world; private final long expiry; - private final String contexts; + private final Multimap contexts; + + public String serialiseContext() { + return GSON.toJson(getContexts().asMap()); + } public Node toNode() { NodeBuilder builder = new NodeBuilder(permission); @@ -70,17 +86,8 @@ public class NodeDataHolder { builder.setWorld(world); builder.setExpiry(expiry); - try { - Map> deserializedContexts = GSON.fromJson(contexts, CONTEXT_TYPE); - if (deserializedContexts != null && !deserializedContexts.isEmpty()) { - for (Map.Entry> c : deserializedContexts.entrySet()) { - for (String val : c.getValue()) { - builder.withExtraContext(c.getKey(), val); - } - } - } - } catch (Exception e) { - e.printStackTrace(); + for (Map.Entry e : contexts.entries()) { + builder.withExtraContext(e); } return builder.build(); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/holder/HeldPermission.java b/common/src/main/java/me/lucko/luckperms/common/storage/holder/HeldPermission.java new file mode 100644 index 000000000..3f2a3899f --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/storage/holder/HeldPermission.java @@ -0,0 +1,40 @@ +/* + * 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.common.storage.holder; + +import com.google.common.collect.Multimap; + +import java.util.Optional; +import java.util.OptionalLong; + +public interface HeldPermission { + + T getHolder(); + String getPermission(); + boolean getValue(); + Optional getServer(); + Optional getWorld(); + OptionalLong getExpiry(); + Multimap getContext(); + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/holder/NodeHeldPermission.java b/common/src/main/java/me/lucko/luckperms/common/storage/holder/NodeHeldPermission.java new file mode 100644 index 000000000..467983351 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/storage/holder/NodeHeldPermission.java @@ -0,0 +1,77 @@ +/* + * 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.common.storage.holder; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +import com.google.common.collect.Multimap; + +import me.lucko.luckperms.api.Node; +import me.lucko.luckperms.common.storage.backing.utils.NodeDataHolder; + +import java.util.Optional; +import java.util.OptionalLong; + +@Getter +@EqualsAndHashCode +@AllArgsConstructor(staticName = "of") +public class NodeHeldPermission implements HeldPermission { + public static NodeHeldPermission of(T holder, NodeDataHolder nodeDataHolder) { + return of(holder, nodeDataHolder.toNode()); + } + + private final T holder; + private final Node node; + + @Override + public String getPermission() { + return node.getPermission(); + } + + @Override + public boolean getValue() { + return node.getValue(); + } + + @Override + public Optional getServer() { + return node.getServer(); + } + + @Override + public Optional getWorld() { + return node.getWorld(); + } + + @Override + public OptionalLong getExpiry() { + return node.isTemporary() ? OptionalLong.of(node.getExpiryUnixTime()) : OptionalLong.empty(); + } + + @Override + public Multimap getContext() { + return node.getContexts().toMultimap(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/TolerantStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/TolerantStorage.java index 16cd7db2e..fff2c0f3b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/TolerantStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/TolerantStorage.java @@ -32,7 +32,9 @@ import me.lucko.luckperms.common.core.model.Track; import me.lucko.luckperms.common.core.model.User; import me.lucko.luckperms.common.data.Log; import me.lucko.luckperms.common.storage.Storage; +import me.lucko.luckperms.common.storage.holder.HeldPermission; +import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -131,6 +133,16 @@ public class TolerantStorage implements Storage { } } + @Override + public CompletableFuture>> getUsersWithPermission(String permission) { + phaser.register(); + try { + return backing.getUsersWithPermission(permission); + } finally { + phaser.arriveAndDeregister(); + } + } + @Override public CompletableFuture createAndLoadGroup(String name) { phaser.register(); @@ -181,6 +193,16 @@ public class TolerantStorage implements Storage { } } + @Override + public CompletableFuture>> getGroupsWithPermission(String permission) { + phaser.register(); + try { + return backing.getGroupsWithPermission(permission); + } finally { + phaser.arriveAndDeregister(); + } + } + @Override public CompletableFuture createAndLoadTrack(String name) { phaser.register();