package fr.pandacube.lib.permissions; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.OptionalLong; import java.util.Set; import java.util.stream.LongStream; import fr.pandacube.lib.chat.ChatTreeNode; import fr.pandacube.lib.permissions.PermissionExpressionParser.LitteralPermissionTester; import fr.pandacube.lib.permissions.PermissionsCachedBackendReader.CachedEntity; import fr.pandacube.lib.permissions.SQLPermissions.EntityType; import fr.pandacube.lib.util.Log; /** * Represents an entity in the permission system, either a group or a player. */ public sealed abstract class PermEntity permits PermPlayer, PermGroup { /* package */ final String name; /* package */ final EntityType type; /* package */ PermEntity(String n, EntityType t) { name = n; type = t; } /* package */ abstract CachedEntity getBackendEntity(); /** * Gets all the groups this entity inherits from. * @return a list of all the groups this entity inherits from. */ public abstract List getInheritances(); /** * Gets all the group names this entity inherits from. * @return a list of all the group names this entity inherits from. */ public abstract List getInheritancesString(); /** * Gets the name of this entity. * @return the name of this entity. */ public abstract String getName(); /** * Gets the name of this entity, as it is stored in the database. * @return the name of this entity, as it is stored in the database. */ public String getInternalName() { return name; } /** * Tells if the current entity inherits directly or indirectly from the specified group. * @param group the group to search for * @param recursive true to search in the inheritance tree, or false to search only in the inheritance list of the current entity. * @return true if the current entity inherits directly or indirectly from the specified group, false otherwise. */ public boolean inheritsFromGroup(String group, boolean recursive) { if (group == null) return false; return getInheritances().stream().anyMatch(g -> g.name.equals(group) || (recursive && g.inheritsFromGroup(group, true))); } /** * Gets the effective prefix of this entity. * It is either the prefix defined directly for this entity, or from inheritance. * @return the effective prefix of this entity. */ public String getPrefix() { return Permissions.resolver.getEffectivePrefix(name, type); } /** * Gets the prefix defined directly for this entity. * @return the prefix defined directly for this entity. */ public String getSelfPrefix() { return getBackendEntity().getSelfPrefix(); } /** * Provides informations on how the effective prefix of this entity is determined. * @return a {@link ChatTreeNode} providing informations on how the effective prefix of this entity is determined. */ public ChatTreeNode debugPrefix() { return Permissions.resolver.debugPrefix(name, type); } /** * Sets the prefix of this entity. * @param prefix the prefix for this entity. */ public void setSelfPrefix(String prefix) { Permissions.backendWriter.setSelfPrefix(name, type, prefix); } /** * Gets the effective suffix of this entity. * It is either the suffix defined directly for this entity, or from inheritance. * @return the effective suffix of this entity. */ public String getSuffix() { return Permissions.resolver.getEffectiveSuffix(name, type); } /** * Gets the suffix defined directly for this entity. * @return the suffix defined directly for this entity. */ public String getSelfSuffix() { return getBackendEntity().getSelfSuffix(); } /** * Provides informations on how the effective suffix of this entity is determined. * @return a {@link ChatTreeNode} providing informations on how the effective suffix of this entity is determined. */ public ChatTreeNode debugSuffix() { return Permissions.resolver.debugSuffix(name, type); } /** * Sets the suffix of this entity. * @param suffix the suffix for this entity. */ public void setSelfSuffix(String suffix) { Permissions.backendWriter.setSelfSuffix(name, type, suffix); } /** * Gets the effective list of permissions that applies to this entity out of a specific server and world. * It is either the permissions defined directly for this entity, or from inheritance as long as they are not * overriden. * @return the effective list of permissions that applies to this entity out of a specific server and world. */ public Map listEffectivePermissions() { return listEffectivePermissions(null, null); } /** * Gets the effective list of permissions that applies to this entity on a specific server. * It is either the permissions defined directly for this entity, or from inheritance as long as they are not * overriden. * @param server the server where the returned permissions apply for this entity. * @return the effective list of permissions that applies to this entity on a specific server. */ public Map listEffectivePermissions(String server) { return listEffectivePermissions(server, null); } /** * Gets the effective list of permissions that applies to this entity on a specific server and world. * It is either the permissions defined directly for this entity, or from inheritance as long as they are not * overriden. * @param server the server containing the world where the returned permissions apply for this entity. * @param world the world in the server where the returned permissions apply for this entity. * @return the effective list of permissions that applies to this entity on a specific server and world. */ public Map listEffectivePermissions(String server, String world) { return Permissions.resolver.getEffectivePermissionList(name, type, server, world); } /** * Gets the effective values of the provided permission range prefix that applies to this entity out of a specific * server and world. * It is either the range values defined directly for this entity, or from inheritance as long as they are not * overriden. * @param permissionPrefix the permission range prefix. * @return the effective values of the provided permission range prefix that applies to this entity out of a * specific server and world. */ public LongStream getPermissionRangeValues(String permissionPrefix) { return getPermissionRangeValues(permissionPrefix, null, null); } /** * Gets the effective values of the provided permission range prefix that applies to this entity on a specific * server. * It is either the range values defined directly for this entity, or from inheritance as long as they are not * overriden. * @param permissionPrefix the permission range prefix. * @param server the server where the returned values apply for this entity. * @return the effective values of the provided permission range prefix that applies to this entity on a specific * server. */ public LongStream getPermissionRangeValues(String permissionPrefix, String server) { return getPermissionRangeValues(permissionPrefix, server, null); } /** * Gets the effective values of the provided permission range prefix that applies to this entity on a specific * server and world. * It is either the range values defined directly for this entity, or from inheritance as long as they are not * overriden. * @param permissionPrefix the permission range prefix. * @param server the server containing the world where the returned values apply for this entity. * @param world the world in the server where the returned values apply for this entity. * @return the effective values of the provided permission range prefix that applies to this entity on a specific * server and world. */ public LongStream getPermissionRangeValues(String permissionPrefix, String server, String world) { String prefixWithEndingDot = permissionPrefix.endsWith(".") ? permissionPrefix : (permissionPrefix + "."); int prefixLength = prefixWithEndingDot.length(); return listEffectivePermissions(server, world).entrySet().stream() .filter(Map.Entry::getValue) // permission must be positive .map(Map.Entry::getKey) // keep only the permission node (key), since the value is always true .filter(p -> p.startsWith(prefixWithEndingDot)) // keep only relevant permissions .map(p -> p.substring(prefixLength)) // keep only what is after the prefix .map(suffix -> { // convert to long try { return Long.parseLong(suffix); } catch (NumberFormatException e) { return null; } }) .filter(Objects::nonNull) .mapToLong(longSuffix -> longSuffix) .sorted(); } /** * Gets the maximum effective value of the provided permission range prefix that applies to this entity out of a * specific server and world. * It is either the range values defined directly for this entity, or from inheritance as long as they are not * overriden. * @param permissionPrefix the permission range prefix. * @return the maximum effective value of the provided permission range prefix that applies to this entity out of a * specific server and world. */ public OptionalLong getPermissionRangeMax(String permissionPrefix) { return getPermissionRangeMax(permissionPrefix, null, null); } /** * Gets the maximum effective value of the provided permission range prefix that applies to this entity on a * specific server. * It is either the range values defined directly for this entity, or from inheritance as long as they are not * overriden. * @param permissionPrefix the permission range prefix. * @param server the server where the returned value applies for this entity. * @return the maximum effective value of the provided permission range prefix that applies to this entity on a * specific server. */ public OptionalLong getPermissionRangeMax(String permissionPrefix, String server) { return getPermissionRangeMax(permissionPrefix, server, null); } /** * Gets the maximum effective value of the provided permission range prefix that applies to this entity on a * specific server and world. * It is either the range values defined directly for this entity, or from inheritance as long as they are not * overriden. * @param permissionPrefix the permission range prefix. * @param server the server containing the world where the returned value applies for this entity. * @param world the world in the server where the returned value applies for this entity. * @return the maximum effective value of the provided permission range prefix that applies to this entity on a * specific server and world. */ public OptionalLong getPermissionRangeMax(String permissionPrefix, String server, String world) { return getPermissionRangeValues(permissionPrefix, server, world).max(); } /** * Tells if this entity has the provided permission out of a specific server and world. * It is either based on the permissions defined directly for this entity, or from inheritance as long as they are * not overriden. * @param permission the permission to ckeck on this entity. * @return true if this entity has the permission, false if it is negated, or null if not known. */ public Boolean hasPermission(String permission) { return hasPermission(permission, null, null); } /** * Tells if this entity has the provided permission on a specitif server. * It is either based on the permissions defined directly for this entity, or from inheritance as long as they are * not overriden. It also consider permissions that apply on any server. * @param permission the permission to ckeck on this entity. * @param server the server in which to test the permission for this entity. * @return true if this entity has the permission, false if it is negated, or null if not known. */ public Boolean hasPermission(String permission, String server) { return hasPermission(permission, server, null); } /** * Tells if this entity has the provided permission on a specitif server and world. * It is either based on the permissions defined directly for this entity, or from inheritance as long as they are * not overriden. It also consider permissions that apply on any world of that server, and then any server. * @param permission the permission to ckeck on this entity. * @param server the server in which to test the permission for this entity. * @param world the world in which to test the permission for this entity. * @return true if this entity has the permission, false if it is negated, or null if not known. */ public Boolean hasPermission(String permission, String server, String world) { Boolean ret = Permissions.resolver.getEffectivePermission(name, type, permission, server, world); Log.debug("[Perm] For " + type.toString().toLowerCase() + " " + getName() + ", '" + permission + "' is " + ret); return ret; } /** * Tells if this entity has the provided permission on a specitif server and world. * It is either based on the permissions defined directly for this entity, or from inheritance as long as they are * not overriden. * @param permission the permission to ckeck on this entity. * @param server the server in which to test the permission for this entity. * @param world the world in which to test the permission for this entity. * @param deflt the default value is the permission is undefined for this entity. * @return true if this entity has the permission, false if it is negated, or {@code deflt} if not known. */ public boolean hasPermissionOr(String permission, String server, String world, boolean deflt) { Boolean ret = hasPermission(permission, server, world); return ret != null ? ret : deflt; } /** * Evaluates the provided permission expression for this entity. * It uses {@link #hasPermissionOr(String, String, String, boolean)} with {@code false} as a default value, to check * each permission nodes individualy. * @param permExpression the permission expression to evaluate on this entity. * @param server the server in which to test the permission expression for this entity. * @param world the world in which to test the permission expression for this entity. * @return true if this the permission expression evaluates to true, false otherwise. * @see PermissionExpressionParser#evaluate(String, LitteralPermissionTester) */ public boolean hasPermissionExpression(String permExpression, String server, String world) { return PermissionExpressionParser.evaluate(permExpression, p -> hasPermissionOr(p, server, world, false)); } /** * Provides informations on how the effective permission of this entity on the provided permission node is * determined. * @param permission the permission node to debug on this entity. * @return a {@link ChatTreeNode} providing informations on how the effective permission is determined. */ public ChatTreeNode debugPermission(String permission) { return debugPermission(permission, null, null); } /** * Provides informations on how the effective permission of this entity on the provided permission node is * determined. * @param permission the permission node to debug on this entity. * @param server the server in which to test the permission for this entity. * @return a {@link ChatTreeNode} providing informations on how the effective permission is determined. */ public ChatTreeNode debugPermission(String permission, String server) { return debugPermission(permission, server, null); } /** * Provides informations on how the effective permission of this entity on the provided permission node is * determined. * @param permission the permission node to debug on this entity. * @param server the server in which to test the permission for this entity. * @param world the world in which to test the permission for this entity. * @return a {@link ChatTreeNode} providing informations on how the effective permission is determined. */ public ChatTreeNode debugPermission(String permission, String server, String world) { return Permissions.resolver.debugPermission(name, type, permission, server, world); } /** * Adds the provided permission node to this entity that apply on any server. * @param permission the permission node to add. * @throws IllegalStateException if the permission is already set. */ public void addSelfPermission(String permission) { addSelfPermission(permission, null, null); } /** * Adds the provided permission node to this entity that apply on the provided server. * @param permission the permission node to add. * @param server the server in which to apply the permission. * @throws IllegalStateException if the permission is already set. */ public void addSelfPermission(String permission, String server) { addSelfPermission(permission, server, null); } /** * Adds the provided permission node to this entity that apply on the provided server and world. * @param permission the permission node to add. * @param server the server in which to apply the permission. * @param world the world in which to apply the permission. * @throws IllegalStateException if the permission is already set. */ public void addSelfPermission(String permission, String server, String world) { Permissions.backendWriter.addSelfPermission(name, type, permission, server, world); } /** * Removes the provided permission node from this entity that applied on any server. * @param permission the permission node to add. * @throws IllegalStateException if the permission was not set. */ public void removeSelfPermission(String permission) { removeSelfPermission(permission, null, null); } /** * Removes the provided permission node from this entity that applied on the provided server. * @param permission the permission node to remove. * @param server the server from which to remove the permission. * @throws IllegalStateException if the permission was not set. */ public void removeSelfPermission(String permission, String server) { removeSelfPermission(permission, server, null); } /** * Removes the provided permission node from this entity that applied on the provided server and world. * @param permission the permission node to remove. * @param server the server from which to remove the permission. * @param world the world from which to remove the permission. * @throws IllegalStateException if the permission was not set. */ public void removeSelfPermission(String permission, String server, String world) { Permissions.backendWriter.removeSelfPermission(name, type, permission, server, world); } /** * Counts the number of self permission nodes for this entity. * @return the number of self permission nodes for this entity. */ public int getSelfPermissionsCount() { return getSelfPermissionsServerWorldKeys().stream() .mapToInt(key -> getSelfPermissions(key.server(), key.world()).size()) .sum(); } /** * Gets all the server/world attribution that have at least one self permission for this entity. * @return all the server/world attribution that have at least one self permission for this entity. */ public Set getSelfPermissionsServerWorldKeys() { return getBackendEntity().getSelfPermissionsServerWorldKeys(); } /** * Gets all the self permission nodes that apply everywhere for this entity. * @return all the self permission nodes that apply everywhere for this entity. */ public List getSelfPermissions() { return getSelfPermissions(null, null); } /** * Gets all the self permission nodes that apply on the provided server for this entity. * @param server the server from which to get the permissions. * @return all the self permission nodes that apply on the provided server for this entity. */ public List getSelfPermissions(String server) { return getSelfPermissions(server, null); } /** * Gets all the self permission nodes that apply on the provided server and world for this entity. * @param server the server from which to get the permissions. * @param world the world from which to get the permissions. * @return all the self permission nodes that apply on the provided server and world for this entity. */ public List getSelfPermissions(String server, String world) { return getBackendEntity().getSelfPermissions(server, world); } @Override public boolean equals(Object obj) { return obj instanceof PermEntity o && Objects.equals(name, o.name) && type == o.type; } @Override public int hashCode() { return Objects.hash(name, type); } }