diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/PermissionsProvider.java b/api/src/main/java/me/lokka30/treasury/api/permission/PermissionsProvider.java new file mode 100644 index 00000000..29ced230 --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/PermissionsProvider.java @@ -0,0 +1,27 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission; + +import java.util.Collection; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import me.lokka30.treasury.api.common.NamespacedKey; +import me.lokka30.treasury.api.permission.node.holder.NodeHolderGroup; +import me.lokka30.treasury.api.permission.node.holder.NodeHolderPlayer; +import org.jetbrains.annotations.NotNull; + +public interface PermissionsProvider { + + @NotNull CompletableFuture retrievePlayerNodeHolder(@NotNull UUID uuid); + + @NotNull CompletableFuture> allPlayerNodeHolderIds(); + + @NotNull CompletableFuture retrieveOrCreateGroup(@NotNull NamespacedKey groupId); + + @NotNull CompletableFuture> allGroupNodeHolderIds(); + + @NotNull NodeHolderGroup defaultGroup(); + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/context/Context.java b/api/src/main/java/me/lokka30/treasury/api/permission/context/Context.java new file mode 100644 index 00000000..f14e23c6 --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/context/Context.java @@ -0,0 +1,69 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.context; + +import java.util.Objects; +import java.util.function.BiPredicate; +import me.lokka30.treasury.api.common.NamespacedKey; +import me.lokka30.treasury.api.permission.node.holder.NodeHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a context, in which a specific thing, a {@link me.lokka30.treasury.api.permission.node.Node} for example, applies. + * + * @author Ivan Pekov + */ +public interface Context { + + /** + * Returns the global context. If only this context is applied to a + * {@link me.lokka30.treasury.api.permission.node.Node} for example, that node will always + * apply without any other interference. + */ + Context GLOBAL = Context.of(NamespacedKey.of("treasury", "global"), ($, $1) -> true); + + /** + * Creates a new context. + * + * @param key context key + * @param condition context condition + * @return new context + */ + @Contract(value = "_, _ -> new", pure = true) + @NotNull + static Context of( + @NotNull NamespacedKey key, @NotNull BiPredicate condition + ) { + Objects.requireNonNull(key, "key"); + Objects.requireNonNull(condition, "condition"); + return new Context() { + @Override + public @NotNull NamespacedKey getKey() { + return key; + } + + @Override + public @NotNull BiPredicate getCondition() { + return condition; + } + }; + } + + /** + * Returns the {@link NamespacedKey key} of this context. + * + * @return key + */ + @NotNull NamespacedKey getKey(); + + /** + * Returns the condition under which this context will apply. + * + * @return condition + */ + @NotNull BiPredicate getCondition(); + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/context/ContextSet.java b/api/src/main/java/me/lokka30/treasury/api/permission/context/ContextSet.java new file mode 100644 index 00000000..03381bb8 --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/context/ContextSet.java @@ -0,0 +1,147 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.context; + +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import me.lokka30.treasury.api.common.NamespacedKey; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a set of {@link Context contexts}, which can be applied for a + * {@link me.lokka30.treasury.api.permission.node.Node}. + *

Class is immutable. + * + * @author Ivan Pekov + */ +public final class ContextSet implements Iterable { + + private static final ContextSet GLOBAL = new ContextSet(Collections.singletonMap( + Context.GLOBAL.getKey(), + Context.GLOBAL + )); + private static final ContextSet EMPTY = new ContextSet(Collections.emptyMap()); + + /** + * Returns the empty context set constant. + * + * @return empty context set + */ + @NotNull + public static ContextSet empty() { + return EMPTY; + } + + /** + * Returns the context set constant, which has only 1 context, and that is the + * {@link Context#GLOBAL global} context. + * + * @return global context set + */ + @NotNull + public static ContextSet global() { + return GLOBAL; + } + + /** + * Creates a new context set of the specified {@link Context contexts} + * + * @param contexts contexts the created context set will contain + * @return new context set + */ + @NotNull + public static ContextSet of(@NotNull Context @NotNull ... contexts) { + Objects.requireNonNull(contexts, "contexts"); + if (contexts.length == 0) { + return empty(); + } + Map map = new ConcurrentHashMap<>(); + for (Context context : contexts) { + map.put(context.getKey(), context); + } + return new ContextSet(map); + } + + private Map contexts; + + @Contract(pure = true) + private ContextSet(Map contexts) { + this.contexts = contexts; + } + + /** + * Returns a {@link Optional}, which will be fulfilled with a {@link Context} if this context + * set holds a context, identified by the specified {@code contextKey}. + * + * @param contextKey context key + * @return context if such is found, empty optional otherwise + */ + @NotNull + public Optional getContext(@NotNull NamespacedKey contextKey) { + Objects.requireNonNull(contextKey, "contextKey"); + return Optional.ofNullable(this.contexts.get(contextKey)); + } + + /** + * Returns whether a {@link Context} is held under the specified {@code contextKey} in this + * context set. + * + * @param contextKey context key + * @return true if context is held, false otherwise + */ + public boolean hasContext(@NotNull NamespacedKey contextKey) { + Objects.requireNonNull(contextKey, "contextKey"); + return contexts.containsKey(contextKey); + } + + /** + * Returns this context set as a mutable {@link Set}. Modifying the returned set will not + * affect the context set object this method is called from. + * + * @return set copy representation of this context set + */ + @NotNull + public Set asSet() { + if (this.contexts.isEmpty()) { + return Collections.emptySet(); + } + Set ret = ConcurrentHashMap.newKeySet(); + ret.addAll(this.contexts.values()); + return ret; + } + + /** + * {@inheritDoc} + */ + @NotNull + @Override + public Iterator iterator() { + Iterator handle = this.contexts.values().iterator(); + // Iterator#remove default impl throws a UnsupportedOperationException which suits our needs + // we don't return this.contexts.values().iterator() directly as it is likely to have a + // remove() impl + return new Iterator() { + @Override + public boolean hasNext() { + return handle.hasNext(); + } + + // NotNull contract because per Iterator javadoc, Iterator#next throws + // NoSuchElementException if !hasNext() = true + @NotNull + @Override + public Context next() { + return handle.next(); + } + }; + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeEvent.java b/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeEvent.java new file mode 100644 index 00000000..18900481 --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeEvent.java @@ -0,0 +1,66 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.events; + +import me.lokka30.treasury.api.common.Cause; +import me.lokka30.treasury.api.permission.node.Node; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +public class NodeEvent { + + private Result result; + + public NodeEvent(@NotNull Result initialResult) { + this.result = initialResult; + } + + @NotNull + public Node getNode() { + return result.getNode(); + } + + @NotNull + public Cause getCause() { + return result.getCause(); + } + + @NotNull + public Result asResult() { + return this.result; + } + + public void withNewResult(@NotNull Result result) { + this.result = result; + } + + public static class Result { + + @NotNull + @Contract(value = "_, _ -> new", pure = true) + public static Result of(@NotNull Node node, @NotNull Cause cause) { + return new Result(node, cause); + } + + private final Node node; + private final Cause cause; + + private Result(@NotNull Node node, @NotNull Cause cause) { + this.node = node; + this.cause = cause; + } + + @NotNull + public Node getNode() { + return this.node; + } + + @NotNull + public Cause getCause() { + return this.cause; + } + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeRemoveEvent.java b/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeRemoveEvent.java new file mode 100644 index 00000000..86f95c65 --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeRemoveEvent.java @@ -0,0 +1,26 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.events; + +import me.lokka30.treasury.api.permission.node.holder.NodeHolder; +import org.jetbrains.annotations.NotNull; + +public class NodeRemoveEvent extends NodeEvent { + + private final NodeHolder nodeHolder; + + public NodeRemoveEvent( + @NotNull NodeHolder nodeHolder, @NotNull NodeEvent.Result initialResult + ) { + super(initialResult); + this.nodeHolder = nodeHolder; + } + + @NotNull + public NodeHolder getNodeHolder() { + return this.nodeHolder; + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeUpdateEvent.java b/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeUpdateEvent.java new file mode 100644 index 00000000..64ad58bc --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/events/NodeUpdateEvent.java @@ -0,0 +1,26 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.events; + +import me.lokka30.treasury.api.permission.node.holder.NodeHolder; +import org.jetbrains.annotations.NotNull; + +public class NodeUpdateEvent extends NodeEvent { + + private final NodeHolder nodeHolder; + + public NodeUpdateEvent( + @NotNull NodeHolder nodeHolder, @NotNull NodeEvent.Result initialResult + ) { + super(initialResult); + this.nodeHolder = nodeHolder; + } + + @NotNull + public NodeHolder getNodeHolder() { + return nodeHolder; + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/node/DefaultPermissionNodeImpl.java b/api/src/main/java/me/lokka30/treasury/api/permission/node/DefaultPermissionNodeImpl.java new file mode 100644 index 00000000..766b68fb --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/node/DefaultPermissionNodeImpl.java @@ -0,0 +1,76 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.node; + +import java.util.Optional; +import me.lokka30.treasury.api.common.misc.TriState; +import me.lokka30.treasury.api.permission.context.ContextSet; +import me.lokka30.treasury.api.permission.node.holder.NodeHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class DefaultPermissionNodeImpl implements PermissionNode { + + private final String key; + private final int weight; + private final TriState value; + private final boolean inherited; + private final NodeHolder inheritedFrom, owner; + private final ContextSet contextSet; + + DefaultPermissionNodeImpl( + @NotNull String key, + int weight, + @NotNull TriState value, + boolean inherited, + @Nullable NodeHolder inheritedFrom, + @Nullable NodeHolder owner, + @Nullable ContextSet contextSet + ) { + this.key = key; + this.weight = weight; + this.value = value; + this.inherited = inherited; + this.inheritedFrom = inheritedFrom; + this.owner = owner; + this.contextSet = contextSet; + } + + @Override + public @NotNull String key() { + return key; + } + + @Override + public int weight() { + return weight; + } + + @Override + public @NotNull TriState value() { + return value; + } + + @Override + public boolean isInherited() { + return inherited; + } + + @Override + public @NotNull Optional inheritedFrom() { + return Optional.ofNullable(inheritedFrom); + } + + @Override + public @NotNull Optional owner() { + return Optional.ofNullable(owner); + } + + @Override + public @NotNull ContextSet contextSet() { + return contextSet == null ? ContextSet.empty() : contextSet; + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/node/Node.java b/api/src/main/java/me/lokka30/treasury/api/permission/node/Node.java new file mode 100644 index 00000000..78d2a20e --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/node/Node.java @@ -0,0 +1,271 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.node; + +import java.util.Optional; +import me.lokka30.treasury.api.permission.context.ContextSet; +import me.lokka30.treasury.api.permission.node.holder.NodeHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +/** + * A {@code Node} represents an object, holding specific information, which can be classified + * under so-called "permissions". + * + * @author Ivan Pekov + */ +public interface Node { + + /** + * Returns the {@link Type} of the node. + * + * @return node type + */ + @NotNull Type type(); + + /** + * Returns the {@link String string} key representation of this node + * + * @return key + */ + @NotNull String key(); + + /** + * Returns the weight of this node. A weight represents how effective is this node compared + * to others. + *

+ * For an example, lets say a {@link NodeHolder node holder} has a node with weight 1 that + * permits the usage of the "/give" command. That same node holder also has a node with + * weight 2 that disallows the usage of the "/give" command. The node with the biggest weight + * is to be applied, hence that specific node holder should NOT be able to use the + * "/give" command. + * + * @return node weight + */ + int weight(); + + /** + * Returns whether this node is inherited. + *

+ * By "inherited" is meant that if that node is retrieved from a {@link NodeHolder node holder} + * instance (e.g. {@link #owner()} {@link Optional#isPresent()} returns {@code true}), does + * that node holder get this node from a parent node holder (say a parent node holder can be + * a {@link me.lokka30.treasury.api.permission.node.holder.NodeHolderGroup group node holder}). + * + * @return is the node inherited + */ + boolean isInherited(); + + /** + * Returns the {@link NodeHolder node holder} from which this node is inherited from. + * + * @return node holder owner of this node if present, {@link Optional#empty()} otherwise + */ + @NotNull Optional inheritedFrom(); + + /** + * Returns the {@link NodeHolder node holder} owner (origin) of that node. + * + * @return owner if present, {@link Optional#empty()} otherwise + */ + @NotNull Optional owner(); + + /** + * Returns the {@link ContextSet context set}, for which if matched this node applies. + * + * @return context set + */ + @NotNull ContextSet contextSet(); + + /** + * Represents a {@link Node} type. + *

+ * This class can be extended to allow for more robust type implementations. + * + * @author Ivan Pekov + */ + class Type { // not final to allow custom nodes :) + + /** + * Returns the {@link PermissionNode} type. + */ + public static final Type PERMISSION = new Type(PermissionNode.class); + + /** + * Returns the {@link PrefixNode} type. + */ + public static final Type PREFIX = new Type(PrefixNode.class); + + /** + * Returns the {@link SuffixNode} type. + */ + public static final Type SUFFIX = new Type(SuffixNode.class); + + private final Class nodeClass; + + /** + * Construct a new type. + * + * @param nodeClass the node class to which this type applies to. + */ + public Type(@NotNull Class nodeClass) { + this.nodeClass = nodeClass; + } + + /** + * Returns the {@link Class node class} this type applies to. + * + * @return node class + */ + @NotNull + public Class getNodeClass() { + return nodeClass; + } + + } + + /** + * Represents an abstract representation of a builder for a {@link Node}. + * + * @param the node built + * @param the value type of the node type built + * @author Ivan Pekov + */ + abstract class Builder { + + protected String key; + protected ValueType value; + protected int weight; + protected boolean inherited; + protected NodeHolder owner, inheritedFrom; + protected ContextSet contextSet; + + /** + * Create a new empty node builder + */ + public Builder() { + } + + /** + * Create a node builder which is a copy from an existing node. + * + * @param fromNode node to copy data from + */ + public Builder(@NotNull NodeType fromNode) { + this.key = fromNode.key(); + this.weight = fromNode.weight(); + this.inherited = fromNode.isInherited(); + this.inheritedFrom = fromNode.inheritedFrom().orElse(null); + this.owner = fromNode.owner().orElse(null); + this.contextSet = fromNode.contextSet(); + } + + /** + * Create a node builder copy from an existing builder. + * + * @param other other builder to copy values from + */ + public Builder(@NotNull Builder other) { + this.key = other.key; + this.value = other.value; + this.weight = other.weight; + this.inherited = other.inherited; + this.inheritedFrom = other.inheritedFrom; + this.owner = other.owner; + this.contextSet = other.contextSet; + } + + /** + * Copy this node builder in another. + * + * @return a new instance copy of this builder + */ + @Contract("-> new") + @NotNull + public abstract Builder copy(); + + /** + * Specify a key of the built node. + * + * @param key key + * @return this builder instance for chaining + */ + @Contract("_ -> this") + public Builder withKey(@NotNull String key) { + this.key = key; + return this; + } + + /** + * Specify a value of the built node. + * + * @param value value + * @return this builder instance for chaining + */ + @Contract("_ -> this") + public Builder withValue(@NotNull ValueType value) { + this.value = value; + return this; + } + + /** + * Specify the weight of the built node. + * + * @param weight weight + * @return this builder instance for chaining + */ + @Contract("_ -> this") + public Builder withWeight(int weight) { + this.weight = weight; + return this; + } + + /** + * Specify a {@link NodeHolder owner} of the built node. + * + * @param owner owner + * @return this builder instance for chaining + */ + @Contract("_ -> this") + public Builder withOwner(@NotNull NodeHolder owner) { + this.owner = owner; + return this; + } + + /** + * Specify a {@link NodeHolder parent} of the built node. + * + * @param inheritedFrom where this node is inherited from + * @return this builder instance for chaining + */ + @Contract("_ -> this") + public Builder withInheritedFrom(@NotNull NodeHolder inheritedFrom) { + this.inherited = true; + this.inheritedFrom = inheritedFrom; + return this; + } + + /** + * Specify a {@link ContextSet context set} for the built node. + * + * @param contextSet the context set of the node + * @return this builder instance for chaining + */ + @Contract("_ -> this") + public Builder withContextSet(@NotNull ContextSet contextSet) { + this.contextSet = contextSet; + return this; + } + + /** + * Builds this builder into the needed node. + * + * @return freshly built node + */ + @NotNull + public abstract NodeType build(); + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/node/PermissionNode.java b/api/src/main/java/me/lokka30/treasury/api/permission/node/PermissionNode.java new file mode 100644 index 00000000..8b7420c3 --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/node/PermissionNode.java @@ -0,0 +1,112 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.node; + +import java.util.Objects; +import me.lokka30.treasury.api.common.misc.TriState; +import me.lokka30.treasury.api.permission.context.ContextSet; +import me.lokka30.treasury.api.permission.node.holder.NodeHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a permission {@link Node node}. A {@code PermissionNode} is exactly what the name + * says - an indication whether a {@link NodeHolder node holder} has a permit to do something (e + * .g. execute a command). + * + * @author Ivan Pekov + */ +public interface PermissionNode extends Node { + + /** + * Create a new {@code PermissionNode} builder. + * + * @return new permission node builder + */ + @Contract(value = "-> new", pure = true) + @NotNull + static PermissionNode.PermissionNodeBuilder newBuilder() { + return new PermissionNode.PermissionNodeBuilder(); + } + + /** + * Create a new {@code PermissionNode} builder. + * + * @param fromNode a permission node to create the builder from. + * @return new permission node builder + */ + @Contract(value = "_ -> new", pure = true) + @NotNull + static PermissionNode.PermissionNodeBuilder newBuilder(@NotNull PermissionNode fromNode) { + return new PermissionNode.PermissionNodeBuilder(fromNode); + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + @NotNull + default Node.Type type() { + return Type.PERMISSION; + } + + /** + * Returns the value, held by this {@code PermissionNode}, represented by a {@link TriState + * tri-state}. + * + * @return value + * @see TriState + */ + @NotNull TriState value(); + + final class PermissionNodeBuilder extends Builder { + + public PermissionNodeBuilder() { + super(); + } + + public PermissionNodeBuilder(@NotNull PermissionNode other) { + super(other); + } + + public PermissionNodeBuilder(@NotNull PermissionNodeBuilder other) { + super(other); + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + public @NotNull Builder copy() { + return new PermissionNodeBuilder(this); + } + + /** + * {@inheritDoc} + * + * @return {@inheritDoc} + */ + @Override + public @NotNull PermissionNode build() { + Objects.requireNonNull(key, "key"); + Objects.requireNonNull(value, "value"); + return new DefaultPermissionNodeImpl( + key, + weight, + value, + inherited, + inheritedFrom, + owner, + contextSet + ); + } + + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/node/PrefixNode.java b/api/src/main/java/me/lokka30/treasury/api/permission/node/PrefixNode.java new file mode 100644 index 00000000..612a95cd --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/node/PrefixNode.java @@ -0,0 +1,18 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.node; + +import org.jetbrains.annotations.NotNull; + +// todo: value type?? +public interface PrefixNode extends Node { + + @Override + @NotNull + default Node.Type type() { + return Type.PREFIX; + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/node/SuffixNode.java b/api/src/main/java/me/lokka30/treasury/api/permission/node/SuffixNode.java new file mode 100644 index 00000000..1df84d51 --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/node/SuffixNode.java @@ -0,0 +1,17 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.node; + +import org.jetbrains.annotations.NotNull; + +// todo: value type?? +public interface SuffixNode extends Node { + + @Override + @NotNull + default Node.Type type() { + return Type.SUFFIX; + } +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolder.java b/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolder.java new file mode 100644 index 00000000..8d5d231f --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolder.java @@ -0,0 +1,77 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.node.holder; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import me.lokka30.treasury.api.common.Cause; +import me.lokka30.treasury.api.common.misc.TriState; +import me.lokka30.treasury.api.permission.context.ContextSet; +import me.lokka30.treasury.api.permission.node.Node; +import me.lokka30.treasury.api.permission.node.PermissionNode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface NodeHolder { + + @Nullable NodeHolder parentNodeHolder(); + + @NotNull CompletableFuture> allNodes(); + + @NotNull CompletableFuture> allNodesKeys(); + + @NotNull + default CompletableFuture> allNodesWithType(@NotNull Class type) { + return allNodes().thenApply(nodes -> { + Set ret = new HashSet<>(); + for (Node node : nodes) { + if (node.type().getNodeClass().isAssignableFrom(type)) { + ret.add((T) node); + } + } + return ret; + }); + } + + @NotNull CompletableFuture hasNode(@NotNull String key); + + @NotNull CompletableFuture> retrieveNode(@NotNull String key); + + @NotNull CompletableFuture insertOrModifyNode(@NotNull Node node, @NotNull Cause cause); + + @NotNull CompletableFuture removeNode(@NotNull String nodeKey, @NotNull Cause cause); + + @NotNull CompletableFuture retrievePermissionValue(@NotNull String permissionNodeKey); + + @NotNull CompletableFuture retrievePermissionValue( + @NotNull String permissionNodeKey, @NotNull ContextSet specificContextSet + ); + + @NotNull + default CompletableFuture hasPermission(@NotNull String permissionNodeKey) { + return retrievePermissionValue(permissionNodeKey).thenApply(state -> state == TriState.TRUE); + } + + @NotNull + default CompletableFuture hasPermission( + @NotNull String permissionNodeKey, @NotNull ContextSet specificContextSet + ) { + return retrievePermissionValue( + permissionNodeKey, + specificContextSet + ).thenApply(state -> state == TriState.TRUE); + + } + + @NotNull + default CompletableFuture hasPermission(@NotNull PermissionNode permissionNode) { + return hasPermission(permissionNode.key(), permissionNode.contextSet()); + } + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolderGroup.java b/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolderGroup.java new file mode 100644 index 00000000..676a11be --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolderGroup.java @@ -0,0 +1,11 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.node.holder; + +import me.lokka30.treasury.api.common.Cause; + +public interface NodeHolderGroup extends NodeHolder, Cause.NonPlayer { + +} diff --git a/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolderPlayer.java b/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolderPlayer.java new file mode 100644 index 00000000..d80047ff --- /dev/null +++ b/api/src/main/java/me/lokka30/treasury/api/permission/node/holder/NodeHolderPlayer.java @@ -0,0 +1,11 @@ +/* + * This file is/was part of Treasury. To read more information about Treasury such as its licensing, see . + */ + +package me.lokka30.treasury.api.permission.node.holder; + +import me.lokka30.treasury.api.common.Cause; + +public interface NodeHolderPlayer extends NodeHolder, Cause.Player { + +}