More progress towards 1.6: add transient permissions

This commit is contained in:
Luck
2016-08-27 22:01:17 +01:00
Unverified
parent 2ea9b36c77
commit 2a305b1c55
17 changed files with 560 additions and 244 deletions
@@ -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
@@ -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;
}
@@ -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);
}
}