More progress towards 1.6: add transient permissions
This commit is contained in:
+35
-9
@@ -26,18 +26,19 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.PermissionHolder;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static me.lucko.luckperms.api.implementation.internal.Utils.*;
|
||||
import static me.lucko.luckperms.core.PermissionHolder.convertToLegacy;
|
||||
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
|
||||
|
||||
/**
|
||||
* Provides a link between {@link PermissionHolder} and {@link me.lucko.luckperms.core.PermissionHolder}
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@SuppressWarnings({"unused", "deprecation"})
|
||||
@AllArgsConstructor
|
||||
public class PermissionHolderLink implements PermissionHolder {
|
||||
|
||||
@@ -50,10 +51,20 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node> getPermissionNodes() {
|
||||
public SortedSet<Node> getPermissions() {
|
||||
return Collections.unmodifiableSortedSet(master.getPermissions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node> getEnduringPermissions() {
|
||||
return Collections.unmodifiableSet(master.getNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node> getTransientPermissions() {
|
||||
return Collections.unmodifiableSet(master.getTransientNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Node> getAllNodes() {
|
||||
return Collections.unmodifiableSet(master.getAllNodes(null));
|
||||
@@ -61,12 +72,17 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getNodes() {
|
||||
return convertToLegacy(master.getNodes());
|
||||
return exportToLegacy(master.getNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(@NonNull Node node) {
|
||||
return master.hasPermission(node);
|
||||
public Tristate hasPermission(@NonNull Node node) {
|
||||
return master.hasPermission(node, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate hasTransientPermission(@NonNull Node node) {
|
||||
return master.hasPermission(node, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,7 +116,7 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inheritsPermission(@NonNull Node node) {
|
||||
public Tristate inheritsPermission(@NonNull Node node) {
|
||||
return master.inheritsPermission(node);
|
||||
}
|
||||
|
||||
@@ -139,6 +155,11 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
master.setPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransientPermission(@NonNull Node node) throws ObjectAlreadyHasException {
|
||||
master.setTransientPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(@NonNull String node, @NonNull boolean value) throws ObjectAlreadyHasException {
|
||||
master.setPermission(checkNode(node), value);
|
||||
@@ -174,6 +195,11 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
master.unsetPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetTransientPermission(@NonNull Node node) throws ObjectLacksException {
|
||||
master.unsetTransientPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPermission(@NonNull String node, @NonNull boolean temporary) throws ObjectLacksException {
|
||||
master.unsetPermission(checkNode(node), temporary);
|
||||
@@ -226,7 +252,7 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getPermissions(String server, String world, Map<String, String> extraContext, boolean includeGlobal, List<String> possibleNodes, boolean applyGroups) {
|
||||
return master.getPermissions(server, world, extraContext, includeGlobal, possibleNodes, applyGroups);
|
||||
return master.exportNodes(server, world, extraContext, includeGlobal, applyGroups, possibleNodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -247,7 +273,7 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getPermanentNodes() {
|
||||
return convertToLegacy(master.getPermanentNodes());
|
||||
return exportToLegacy(master.getPermanentNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ import me.lucko.luckperms.groups.Group;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static me.lucko.luckperms.core.PermissionHolder.convertToLegacy;
|
||||
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
|
||||
|
||||
public class GroupListNodes extends SubCommand<Group> {
|
||||
public GroupListNodes() {
|
||||
@@ -40,7 +40,7 @@ public class GroupListNodes extends SubCommand<Group> {
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
|
||||
Message.LISTNODES.send(sender, group.getName(), Util.permNodesToString(convertToLegacy(group.getPermanentNodes())));
|
||||
Message.LISTNODES.send(sender, group.getName(), Util.permNodesToString(exportToLegacy(group.getPermanentNodes())));
|
||||
Message.LISTNODES_TEMP.send(sender, group.getName(), Util.tempNodesToString(group.getTemporaryNodesLegacy()));
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
+1
-2
@@ -26,7 +26,6 @@ import me.lucko.luckperms.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.commands.*;
|
||||
import me.lucko.luckperms.constants.Message;
|
||||
import me.lucko.luckperms.constants.Permission;
|
||||
import me.lucko.luckperms.core.PermissionHolder;
|
||||
import me.lucko.luckperms.users.User;
|
||||
|
||||
import java.util.List;
|
||||
@@ -41,7 +40,7 @@ public class UserListNodes extends SubCommand<User> {
|
||||
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
|
||||
Message.LISTNODES.send(sender, user.getName(), Util.permNodesToString(convertToLegacy(user.getPermanentNodes())));
|
||||
Message.LISTNODES.send(sender, user.getName(), Util.permNodesToString(exportToLegacy(user.getPermanentNodes())));
|
||||
Message.LISTNODES_TEMP.send(sender, user.getName(), Util.tempNodesToString(user.getTemporaryNodesLegacy()));
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.event.events.GroupRemoveEvent;
|
||||
import me.lucko.luckperms.api.event.events.PermissionNodeExpireEvent;
|
||||
import me.lucko.luckperms.api.event.events.PermissionNodeSetEvent;
|
||||
@@ -38,6 +39,7 @@ import me.lucko.luckperms.groups.Group;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -66,14 +68,195 @@ public abstract class PermissionHolder {
|
||||
@Getter
|
||||
private Set<Node> nodes = ConcurrentHashMap.newKeySet();
|
||||
|
||||
/**
|
||||
* The user/group's transient permissions
|
||||
*/
|
||||
@Getter
|
||||
private Set<Node> transientNodes = ConcurrentHashMap.newKeySet();
|
||||
|
||||
/**
|
||||
* Returns a Set of nodes in priority order
|
||||
* @return the holders transient and permanent nodes
|
||||
*/
|
||||
public SortedSet<Node> getPermissions() {
|
||||
// Returns no duplicate nodes. as in, nodes with the same value.
|
||||
|
||||
TreeSet<Node> permissions = new TreeSet<>(PRIORITY_COMPARATOR);
|
||||
permissions.addAll(nodes);
|
||||
permissions.addAll(transientNodes);
|
||||
|
||||
Iterator<Node> iterator = permissions.descendingIterator(); // TODO check this
|
||||
while (iterator.hasNext()) {
|
||||
Node entry = iterator.next();
|
||||
|
||||
permissions.stream()
|
||||
.filter(entry::equalsIgnoringValue) // The node appears again at a higher priority
|
||||
.forEachOrdered(other -> iterator.remove()); // Remove it.
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes temporary permissions that have expired
|
||||
* @return true if permissions had expired and were removed
|
||||
*/
|
||||
public boolean auditTemporaryPermissions() {
|
||||
boolean work = false;
|
||||
|
||||
Iterator<Node> iterator = nodes.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Node element = iterator.next();
|
||||
if (element.hasExpired()) {
|
||||
iterator.remove();
|
||||
|
||||
work = true;
|
||||
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(this), element));
|
||||
}
|
||||
}
|
||||
|
||||
Iterator<Node> iterator2 = transientNodes.iterator();
|
||||
while (iterator2.hasNext()) {
|
||||
Node element = iterator2.next();
|
||||
if (element.hasExpired()) {
|
||||
iterator2.remove();
|
||||
|
||||
work = true;
|
||||
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(this), element));
|
||||
}
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all of the nodes that this holder has and inherits
|
||||
* @param excludedGroups a list of groups to exclude
|
||||
* @return a set of nodes
|
||||
*/
|
||||
public SortedSet<Node> getAllNodes(List<String> excludedGroups) {
|
||||
SortedSet<Node> all = new ConcurrentSkipListSet<>(PRIORITY_COMPARATOR);
|
||||
all.addAll(getPermissions());
|
||||
|
||||
if (excludedGroups == null) {
|
||||
excludedGroups = new ArrayList<>();
|
||||
}
|
||||
|
||||
excludedGroups.add(getObjectName().toLowerCase());
|
||||
|
||||
Set<String> parents = getPermissions().stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
for (String parent : parents) {
|
||||
Group group = plugin.getGroupManager().get(parent);
|
||||
if (group == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (excludedGroups.contains(group.getObjectName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inherited:
|
||||
for (Node inherited : group.getAllNodes(excludedGroups)) {
|
||||
for (Node existing : all) {
|
||||
if (existing.almostEquals(inherited)) {
|
||||
continue inherited;
|
||||
}
|
||||
}
|
||||
|
||||
all.add(inherited);
|
||||
}
|
||||
}
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all of the nodes that this holder has (and inherits), given the context
|
||||
* @param server the server
|
||||
* @param world the world
|
||||
* @param extraContext any extra context to filter by
|
||||
* @param includeGlobal whether to include global nodes
|
||||
* @param applyGroups if inherited group permissions should be included
|
||||
* @return a map of permissions
|
||||
*/
|
||||
public Set<Node> getAllNodesFiltered(String server, String world, Map<String, String> extraContext, boolean includeGlobal, boolean applyGroups) {
|
||||
Set<Node> perms = ConcurrentHashMap.newKeySet();
|
||||
SortedSet<Node> allNodes;
|
||||
|
||||
if (applyGroups) {
|
||||
allNodes = sort(getAllNodes(null), true);
|
||||
} else {
|
||||
allNodes = sort(getPermissions(), true);
|
||||
}
|
||||
|
||||
for (Node node : allNodes) {
|
||||
if (!node.shouldApplyOnServer(server, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!node.shouldApplyOnWorld(world, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!node.shouldApplyWithContext(extraContext)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
perms.add(node);
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the output of {@link #getAllNodesFiltered(String, String, Map, boolean, boolean)}, and expands wildcards/regex/shorthand perms
|
||||
* @param server the server
|
||||
* @param world the world
|
||||
* @param extraContext any extra context to filter by
|
||||
* @param includeGlobal whether to include global nodes
|
||||
* @param applyGroups if inherited group permissions should be included
|
||||
* @param possibleNodes a list of possible nodes for wildcards and regex permissions
|
||||
* @return a map of permissions
|
||||
*/
|
||||
public Map<String, Boolean> exportNodes(String server, String world, Map<String, String> extraContext, boolean includeGlobal, boolean applyGroups, List<String> possibleNodes) {
|
||||
Map<String, Boolean> perms = new HashMap<>();
|
||||
|
||||
for (Node node : getAllNodesFiltered(server, world, extraContext, includeGlobal, applyGroups)) {
|
||||
perms.put(node.getPermission(), node.getValue());
|
||||
|
||||
if (plugin.getConfiguration().getApplyShorthand()) {
|
||||
node.resolveShorthand().stream()
|
||||
.filter(s -> !perms.containsKey(s))
|
||||
.forEach(s -> perms.put(s, node.getValue()));
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().getApplyWildcards()) {
|
||||
node.resolveWildcard(possibleNodes).stream()
|
||||
.filter(s -> !perms.containsKey(s))
|
||||
.forEach(s -> perms.put(s, node.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(perms);
|
||||
}
|
||||
|
||||
public void setNodes(Set<Node> nodes) {
|
||||
this.nodes.clear();
|
||||
this.nodes.addAll(nodes);
|
||||
auditTemporaryPermissions();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Map<String, Boolean> convertToLegacy(Set<Node> nodes) {
|
||||
public void setTransiestNodes(Set<Node> nodes) {
|
||||
this.transientNodes.clear();
|
||||
this.transientNodes.addAll(nodes);
|
||||
auditTemporaryPermissions();
|
||||
}
|
||||
|
||||
public static Map<String, Boolean> exportToLegacy(Set<Node> nodes) {
|
||||
Map<String, Boolean> m = new HashMap<>();
|
||||
for (Node node : nodes) {
|
||||
m.put(node.toSerializedNode(), node.getValue());
|
||||
@@ -81,6 +264,7 @@ public abstract class PermissionHolder {
|
||||
return Collections.unmodifiableMap(m);
|
||||
}
|
||||
|
||||
// Convenience method
|
||||
private static Node.Builder buildNode(String permission) {
|
||||
return new me.lucko.luckperms.utils.Node.Builder(permission);
|
||||
}
|
||||
@@ -96,84 +280,94 @@ public abstract class PermissionHolder {
|
||||
auditTemporaryPermissions();
|
||||
}
|
||||
|
||||
private static boolean hasPermission(Set<Node> toQuery, Node node) {
|
||||
private static Tristate hasPermission(Set<Node> toQuery, Node node) {
|
||||
for (Node n : toQuery) {
|
||||
if (n.almostEquals(node)) {
|
||||
return true;
|
||||
if (n.equalsIgnoringValue(node)) {
|
||||
n.getTristate();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the holder has a permission node
|
||||
* @param node the node to check
|
||||
* @return true if the holder has the node
|
||||
* @param t whether to check transient nodes
|
||||
* @return a tristate
|
||||
*/
|
||||
public boolean hasPermission(Node node) {
|
||||
return hasPermission(this.nodes, node);
|
||||
public Tristate hasPermission(Node node, boolean t) {
|
||||
return hasPermission(t ? transientNodes : nodes, node);
|
||||
}
|
||||
|
||||
public Tristate hasPermission(Node node) {
|
||||
return hasPermission(node, false);
|
||||
}
|
||||
|
||||
public boolean hasPermission(String node, boolean b) {
|
||||
return hasPermission(buildNode(node).setValue(b).build());
|
||||
return hasPermission(buildNode(node).setValue(b).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean hasPermission(String node, boolean b, String server) {
|
||||
return hasPermission(buildNode(node).setValue(b).setServer(server).build());
|
||||
return hasPermission(buildNode(node).setValue(b).setServer(server).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean hasPermission(String node, boolean b, String server, String world) {
|
||||
return hasPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).build());
|
||||
return hasPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean hasPermission(String node, boolean b, boolean temporary) {
|
||||
return hasPermission(buildNode(node).setValue(b).setExpiry(temporary ? 10L : 0L).build());
|
||||
return hasPermission(buildNode(node).setValue(b).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean hasPermission(String node, boolean b, String server, boolean temporary) {
|
||||
return hasPermission(buildNode(node).setValue(b).setServer(server).setExpiry(temporary ? 10L : 0L).build());
|
||||
return hasPermission(buildNode(node).setValue(b).setServer(server).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean hasPermission(String node, boolean b, String server, String world, boolean temporary) {
|
||||
return hasPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).setExpiry(temporary ? 10L : 0L).build());
|
||||
return hasPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the holder inherits a node
|
||||
* @param node the node to check
|
||||
* @return true if the holder inherits the node
|
||||
* @return a tristate
|
||||
*/
|
||||
public boolean inheritsPermission(Node node) {
|
||||
public Tristate inheritsPermission(Node node) {
|
||||
return hasPermission(getAllNodes(null), node);
|
||||
}
|
||||
|
||||
public boolean inheritsPermission(String node, boolean b) {
|
||||
return inheritsPermission(buildNode(node).setValue(b).build());
|
||||
return inheritsPermission(buildNode(node).setValue(b).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean inheritsPermission(String node, boolean b, String server) {
|
||||
return inheritsPermission(buildNode(node).setValue(b).setServer(server).build());
|
||||
return inheritsPermission(buildNode(node).setValue(b).setServer(server).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean inheritsPermission(String node, boolean b, String server, String world) {
|
||||
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).build());
|
||||
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean inheritsPermission(String node, boolean b, boolean temporary) {
|
||||
return inheritsPermission(buildNode(node).setValue(b).setExpiry(temporary ? 10L : 0L).build());
|
||||
return inheritsPermission(buildNode(node).setValue(b).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean inheritsPermission(String node, boolean b, String server, boolean temporary) {
|
||||
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setExpiry(temporary ? 10L : 0L).build());
|
||||
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
public boolean inheritsPermission(String node, boolean b, String server, String world, boolean temporary) {
|
||||
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).setExpiry(temporary ? 10L : 0L).build());
|
||||
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a permission node
|
||||
* @param node the node to set
|
||||
* @throws ObjectAlreadyHasException if the holder has this permission already
|
||||
*/
|
||||
public void setPermission(Node node) throws ObjectAlreadyHasException {
|
||||
if (hasPermission(node)) {
|
||||
if (hasPermission(node, false) == Tristate.TRUE) {
|
||||
throw new ObjectAlreadyHasException();
|
||||
}
|
||||
|
||||
@@ -181,6 +375,20 @@ public abstract class PermissionHolder {
|
||||
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderLink(this), node));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a transient permission node
|
||||
* @param node the node to set
|
||||
* @throws ObjectAlreadyHasException if the holder has this permission already
|
||||
*/
|
||||
public void setTransientPermission(Node node) throws ObjectAlreadyHasException {
|
||||
if (hasPermission(node, true) == Tristate.TRUE) {
|
||||
throw new ObjectAlreadyHasException();
|
||||
}
|
||||
|
||||
transientNodes.add(node);
|
||||
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderLink(this), node));
|
||||
}
|
||||
|
||||
public void setPermission(String node, boolean value) throws ObjectAlreadyHasException {
|
||||
setPermission(buildNode(node).setValue(value).build());
|
||||
}
|
||||
@@ -211,7 +419,7 @@ public abstract class PermissionHolder {
|
||||
* @throws ObjectLacksException if the holder doesn't have this node already
|
||||
*/
|
||||
public void unsetPermission(Node node) throws ObjectLacksException {
|
||||
if (!hasPermission(node)) {
|
||||
if (hasPermission(node, false) == Tristate.FALSE) {
|
||||
throw new ObjectLacksException();
|
||||
}
|
||||
|
||||
@@ -225,6 +433,26 @@ public abstract class PermissionHolder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets a transient permission node
|
||||
* @param node the node to unset
|
||||
* @throws ObjectLacksException if the holder doesn't have this node already
|
||||
*/
|
||||
public void unsetTransientPermission(Node node) throws ObjectLacksException {
|
||||
if (hasPermission(node, true) == Tristate.FALSE) {
|
||||
throw new ObjectLacksException();
|
||||
}
|
||||
|
||||
transientNodes.remove(node);
|
||||
|
||||
if (node.isGroupNode()) {
|
||||
plugin.getApiProvider().fireEventAsync(new GroupRemoveEvent(new PermissionHolderLink(this),
|
||||
node.getGroupName(), node.getServer().orElse(null), node.getWorld().orElse(null), node.isTemporary()));
|
||||
} else {
|
||||
plugin.getApiProvider().fireEventAsync(new PermissionNodeUnsetEvent(new PermissionHolderLink(this), node));
|
||||
}
|
||||
}
|
||||
|
||||
public void unsetPermission(String node, boolean temporary) throws ObjectLacksException {
|
||||
unsetPermission(buildNode(node).setExpiry(temporary ? 10L : 0L).build());
|
||||
}
|
||||
@@ -253,7 +481,7 @@ public abstract class PermissionHolder {
|
||||
* @return The temporary nodes held by the holder
|
||||
*/
|
||||
public Set<Node> getTemporaryNodes() {
|
||||
return nodes.stream().filter(Node::isTemporary).collect(Collectors.toSet());
|
||||
return getPermissions().stream().filter(Node::isTemporary).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -271,84 +499,18 @@ public abstract class PermissionHolder {
|
||||
* @return The permanent nodes held by the holder
|
||||
*/
|
||||
public Set<Node> getPermanentNodes() {
|
||||
return nodes.stream().filter(Node::isPermanent).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes temporary permissions that have expired
|
||||
* @return true if permissions had expired and were removed
|
||||
*/
|
||||
public boolean auditTemporaryPermissions() {
|
||||
boolean work = false;
|
||||
Iterator<Node> iterator = nodes.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Node element = iterator.next();
|
||||
if (element.hasExpired()) {
|
||||
iterator.remove();
|
||||
|
||||
work = true;
|
||||
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(this), element));
|
||||
}
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all of the nodes that this holder has and inherits
|
||||
* @param excludedGroups a list of groups to exclude
|
||||
* @return a set of nodes
|
||||
*/
|
||||
public Set<Node> getAllNodes(List<String> excludedGroups) {
|
||||
Set<Node> all = ConcurrentHashMap.newKeySet();
|
||||
all.addAll(nodes);
|
||||
|
||||
if (excludedGroups == null) {
|
||||
excludedGroups = new ArrayList<>();
|
||||
}
|
||||
|
||||
excludedGroups.add(getObjectName().toLowerCase());
|
||||
|
||||
Set<String> parents = nodes.stream()
|
||||
.filter(Node::isGroupNode)
|
||||
.map(Node::getGroupName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
for (String parent : parents) {
|
||||
Group group = plugin.getGroupManager().get(parent);
|
||||
if (group == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (excludedGroups.contains(group.getObjectName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inherited:
|
||||
for (Node inherited : group.getAllNodes(excludedGroups)) {
|
||||
for (Node existing : all) {
|
||||
if (existing.almostEquals(inherited)) {
|
||||
continue inherited;
|
||||
}
|
||||
}
|
||||
|
||||
all.add(inherited);
|
||||
}
|
||||
}
|
||||
|
||||
return all;
|
||||
return getPermissions().stream().filter(Node::isPermanent).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't use these methods, only here for compat reasons
|
||||
*/
|
||||
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes) {
|
||||
return getPermissions(server, world, null, plugin.getConfiguration().getIncludeGlobalPerms(), possibleNodes, true);
|
||||
return exportNodes(server, world, null, plugin.getConfiguration().getIncludeGlobalPerms(), true, possibleNodes);
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups) {
|
||||
return getPermissions(server, world, null, plugin.getConfiguration().getIncludeGlobalPerms(), null, true);
|
||||
return exportNodes(server, world, null, plugin.getConfiguration().getIncludeGlobalPerms(), true, null);
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes) {
|
||||
@@ -359,57 +521,6 @@ public abstract class PermissionHolder {
|
||||
return getLocalPermissions(server, null, excludedGroups, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the holders nodes into a Map of permissions to be applied on the platform
|
||||
* @param server the server
|
||||
* @param world the world
|
||||
* @param extraContext any extra context to filter by
|
||||
* @param includeGlobal whether to include global nodes
|
||||
* @param possibleNodes a list of possible permissions for resolving wildcards
|
||||
* @param applyGroups if inherited group permissions should be included
|
||||
* @return a map of permissions
|
||||
*/
|
||||
public Map<String, Boolean> getPermissions(String server, String world, Map<String, String> extraContext, boolean includeGlobal, List<String> possibleNodes, boolean applyGroups) {
|
||||
Map<String, Boolean> perms = new HashMap<>();
|
||||
SortedSet<Node> allNodes;
|
||||
|
||||
if (applyGroups) {
|
||||
allNodes = sort(getAllNodes(null), true);
|
||||
} else {
|
||||
allNodes = sort(nodes, true);
|
||||
}
|
||||
|
||||
for (Node node : allNodes) {
|
||||
if (!node.shouldApplyOnServer(server, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!node.shouldApplyOnWorld(world, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!node.shouldApplyWithContext(extraContext)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
perms.put(node.getPermission(), node.getValue());
|
||||
|
||||
if (plugin.getConfiguration().getApplyShorthand()) {
|
||||
node.resolveShorthand().stream()
|
||||
.filter(s -> !perms.containsKey(s))
|
||||
.forEach(s -> perms.put(s, node.getValue()));
|
||||
}
|
||||
|
||||
if (plugin.getConfiguration().getApplyWildcards()) {
|
||||
node.resolveWildcard(possibleNodes).stream()
|
||||
.filter(s -> !perms.containsKey(s))
|
||||
.forEach(s -> perms.put(s, node.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
public static SortedSet<Node> sort(Set<Node> toSort, boolean reversed) {
|
||||
TreeSet<Node> set = new TreeSet<>(reversed ? PRIORITY_COMPARATOR.reversed() : PRIORITY_COMPARATOR);
|
||||
set.addAll(toSort);
|
||||
@@ -421,41 +532,35 @@ public abstract class PermissionHolder {
|
||||
|
||||
@Override
|
||||
public int compare(Node o1, Node o2) {
|
||||
if (takesPriority(o1, o2)) {
|
||||
return 1;
|
||||
if (o1.isOverride() != o2.isOverride()) {
|
||||
return o1.isOverride() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (takesPriority(o2, o1)) {
|
||||
return -1;
|
||||
if (o1.isServerSpecific() != o2.isServerSpecific()) {
|
||||
return o1.isServerSpecific() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isWorldSpecific() != o2.isWorldSpecific()) {
|
||||
return o1.isWorldSpecific() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isTemporary() != o2.isTemporary()) {
|
||||
return o1.isTemporary() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isWildcard() != o2.isWildcard()) {
|
||||
return o1.isWildcard() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isTemporary()) {
|
||||
return o1.getSecondsTilExpiry() < o2.getSecondsTilExpiry() ? 1 : -1;
|
||||
}
|
||||
|
||||
if (o1.isWildcard()) {
|
||||
return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean takesPriority(Node target, Node over) {
|
||||
if (target.isTemporary() && !over.isTemporary()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target.isWorldSpecific() && !over.isWorldSpecific()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target.isServerSpecific() && !over.isServerSpecific()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!target.isWildcard() && over.isWildcard()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (target.isWildcard() && over.isWildcard()) {
|
||||
if (target.getWildcardLevel() > over.getWildcardLevel()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ public class Group extends PermissionHolder implements Identifiable<String> {
|
||||
*/
|
||||
private List<String> getGroups(String server, String world, boolean includeGlobal) {
|
||||
// Call super #getPermissions method, and just sort through those
|
||||
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal, null, true);
|
||||
Map<String, Boolean> perms = exportNodes(server, world, null, includeGlobal, true, null);
|
||||
return perms.keySet().stream()
|
||||
.filter(s -> Patterns.GROUP_MATCH.matcher(s).matches())
|
||||
.map(s -> Patterns.DOT.split(s, 2)[1])
|
||||
|
||||
@@ -28,7 +28,6 @@ import lombok.Cleanup;
|
||||
import me.lucko.luckperms.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.constants.Constants;
|
||||
import me.lucko.luckperms.core.PermissionHolder;
|
||||
import me.lucko.luckperms.data.Log;
|
||||
import me.lucko.luckperms.groups.Group;
|
||||
import me.lucko.luckperms.storage.Datastore;
|
||||
@@ -188,7 +187,7 @@ public class FlatfileDatastore extends Datastore {
|
||||
writer.name("primaryGroup").value(user.getPrimaryGroup());
|
||||
writer.name("perms");
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, Boolean> e : convertToLegacy(user.getNodes()).entrySet()) {
|
||||
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
|
||||
writer.name(e.getKey()).value(e.getValue().booleanValue());
|
||||
}
|
||||
writer.endObject();
|
||||
@@ -229,7 +228,7 @@ public class FlatfileDatastore extends Datastore {
|
||||
writer.name("primaryGroup").value(user.getPrimaryGroup());
|
||||
writer.name("perms");
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, Boolean> e : convertToLegacy(user.getNodes()).entrySet()) {
|
||||
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
|
||||
writer.name(e.getKey()).value(e.getValue().booleanValue());
|
||||
}
|
||||
writer.endObject();
|
||||
@@ -295,7 +294,7 @@ public class FlatfileDatastore extends Datastore {
|
||||
writer.name("primaryGroup").value(user.getPrimaryGroup());
|
||||
writer.name("perms");
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, Boolean> e : convertToLegacy(user.getNodes()).entrySet()) {
|
||||
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
|
||||
writer.name(e.getKey()).value(e.getValue().booleanValue());
|
||||
}
|
||||
writer.endObject();
|
||||
@@ -323,7 +322,7 @@ public class FlatfileDatastore extends Datastore {
|
||||
writer.name("name").value(group.getName());
|
||||
writer.name("perms");
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, Boolean> e : convertToLegacy(group.getNodes()).entrySet()) {
|
||||
for (Map.Entry<String, Boolean> e : exportToLegacy(group.getNodes()).entrySet()) {
|
||||
writer.name(e.getKey()).value(e.getValue().booleanValue());
|
||||
}
|
||||
writer.endObject();
|
||||
@@ -415,7 +414,7 @@ public class FlatfileDatastore extends Datastore {
|
||||
writer.name("name").value(group.getName());
|
||||
writer.name("perms");
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, Boolean> e : convertToLegacy(group.getNodes()).entrySet()) {
|
||||
for (Map.Entry<String, Boolean> e : exportToLegacy(group.getNodes()).entrySet()) {
|
||||
writer.name(e.getKey()).value(e.getValue().booleanValue());
|
||||
}
|
||||
writer.endObject();
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.mongodb.client.MongoDatabase;
|
||||
import com.mongodb.client.model.InsertOneOptions;
|
||||
import me.lucko.luckperms.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.api.LogEntry;
|
||||
import me.lucko.luckperms.core.PermissionHolder;
|
||||
import me.lucko.luckperms.data.Log;
|
||||
import me.lucko.luckperms.groups.Group;
|
||||
import me.lucko.luckperms.groups.GroupManager;
|
||||
@@ -46,7 +45,7 @@ import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static me.lucko.luckperms.core.PermissionHolder.convertToLegacy;
|
||||
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MongoDBDatastore extends Datastore {
|
||||
@@ -430,7 +429,7 @@ public class MongoDBDatastore extends Datastore {
|
||||
.append("primaryGroup", user.getPrimaryGroup());
|
||||
|
||||
Document perms = new Document();
|
||||
for (Map.Entry<String, Boolean> e : convert(convertToLegacy(user.getNodes())).entrySet()) {
|
||||
for (Map.Entry<String, Boolean> e : convert(exportToLegacy(user.getNodes())).entrySet()) {
|
||||
perms.append(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
@@ -442,7 +441,7 @@ public class MongoDBDatastore extends Datastore {
|
||||
Document main = new Document("_id", group.getName());
|
||||
|
||||
Document perms = new Document();
|
||||
for (Map.Entry<String, Boolean> e : convert(convertToLegacy(group.getNodes())).entrySet()) {
|
||||
for (Map.Entry<String, Boolean> e : convert(exportToLegacy(group.getNodes())).entrySet()) {
|
||||
perms.append(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ public abstract class User extends PermissionHolder implements Identifiable<UUID
|
||||
*/
|
||||
private List<String> getGroups(String server, String world, boolean includeGlobal) {
|
||||
// Call super #getPermissions method, and just sort through those
|
||||
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal, null, true);
|
||||
Map<String, Boolean> perms = exportNodes(server, world, null, includeGlobal, true, null);
|
||||
return perms.keySet().stream()
|
||||
.filter(s -> Patterns.GROUP_MATCH.matcher(s).matches())
|
||||
.map(s -> Patterns.DOT.split(s, 2)[1])
|
||||
|
||||
@@ -24,6 +24,7 @@ package me.lucko.luckperms.utils;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.*;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.constants.Patterns;
|
||||
|
||||
import java.util.*;
|
||||
@@ -85,6 +86,9 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
@Getter
|
||||
private Boolean value;
|
||||
|
||||
@Getter
|
||||
private boolean override;
|
||||
|
||||
private String server = null;
|
||||
private String world = null;
|
||||
|
||||
@@ -101,7 +105,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
* @param world the world this node applies on
|
||||
* @param extraContexts any additional contexts applying to this node
|
||||
*/
|
||||
public Node(String permission, boolean value, long expireAt, String server, String world, Map<String, String> extraContexts) {
|
||||
public Node(String permission, boolean value, boolean override, long expireAt, String server, String world, Map<String, String> extraContexts) {
|
||||
if (permission == null || permission.equals("")) {
|
||||
throw new IllegalArgumentException("Empty permission");
|
||||
}
|
||||
@@ -120,6 +124,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
|
||||
this.permission = permission;
|
||||
this.value = value;
|
||||
this.override = override;
|
||||
this.expireAt = expireAt;
|
||||
this.server = server;
|
||||
this.world = world;
|
||||
@@ -129,6 +134,11 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate getTristate() {
|
||||
return Tristate.fromBoolean(value);
|
||||
}
|
||||
|
||||
public boolean isNegated() {
|
||||
return !value;
|
||||
}
|
||||
@@ -395,6 +405,53 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
return (int) getPermission().chars().filter(num -> num == Character.getNumericValue('.')).count();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalsIgnoringValue(me.lucko.luckperms.api.Node other) {
|
||||
if (!other.getPermission().equalsIgnoreCase(this.getPermission())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (other.isTemporary() != this.isTemporary()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isTemporary()) {
|
||||
if (other.getExpiryUnixTime() != this.getExpiryUnixTime()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (other.getServer().isPresent() != this.getServer().isPresent()) {
|
||||
if (other.getServer().isPresent()) {
|
||||
if (!other.getServer().get().equalsIgnoreCase(this.getServer().get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (other.getWorld().isPresent() != this.getWorld().isPresent()) {
|
||||
if (other.getWorld().isPresent()) {
|
||||
if (!other.getWorld().get().equalsIgnoreCase(this.getWorld().get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!other.getExtraContexts().equals(this.getExtraContexts())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (other.isTemporary() != this.isTemporary()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean almostEquals(me.lucko.luckperms.api.Node other) {
|
||||
if (!other.getPermission().equalsIgnoreCase(this.getPermission())) {
|
||||
@@ -446,6 +503,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
public static class Builder implements me.lucko.luckperms.api.Node.Builder {
|
||||
private final String permission;
|
||||
private Boolean value = true;
|
||||
private boolean override = false;
|
||||
private String server = null;
|
||||
private String world = null;
|
||||
private long expireAt = 0L;
|
||||
@@ -488,6 +546,12 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node.Builder setOverride(boolean override) {
|
||||
this.override = override;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node.Builder setExpiry(long expireAt) {
|
||||
this.expireAt = expireAt;
|
||||
@@ -523,7 +587,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node build() {
|
||||
return new Node(permission, value, expireAt, server, world, extraContexts);
|
||||
return new Node(permission, value, override, expireAt, server, world, extraContexts);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user