Compare commits
5
Commits
v5.5
..
feat/filter
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ecbc473e9 | ||
|
|
73abf64aa3 | ||
|
|
3b5a936674 | ||
|
|
23575d788a | ||
|
|
137775a3de |
No files matched your search
@@ -1,5 +0,0 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
+16
-14
@@ -19,24 +19,26 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
- name: validate gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
uses: gradle/gradle-build-action@v2
|
||||
|
||||
- name: Run build and tests with Gradle wrapper
|
||||
run: ./gradlew test build -PdockerTests
|
||||
|
||||
- name: Publish test report
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
uses: mikepenz/action-junit-report@v3
|
||||
if: success() || failure()
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
@@ -44,7 +46,7 @@ jobs:
|
||||
detailed_summary: true
|
||||
|
||||
- name: Upload all artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: jars
|
||||
path: |
|
||||
@@ -59,7 +61,7 @@ jobs:
|
||||
standalone/loader/build/libs/LuckPerms-Standalone-*.jar
|
||||
|
||||
- name: Upload standalone artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: standalone-binary
|
||||
path: standalone/loader/build/libs/LuckPerms-Standalone-*.jar
|
||||
@@ -74,12 +76,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Retrieve saved standalone jar artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: standalone-binary
|
||||
path: standalone/docker/
|
||||
@@ -88,13 +90,13 @@ jobs:
|
||||
run: mv standalone/docker/LuckPerms-Standalone-*.jar standalone/docker/luckperms-standalone.jar
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -106,7 +108,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
flavor: |
|
||||
@@ -119,7 +121,7 @@ jobs:
|
||||
type=raw,enable=${{ github.ref == 'refs/heads/master' }},value=${{ env.luckperms_version }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: standalone/docker/
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
group = 'net.luckperms'
|
||||
project.version = '5.5'
|
||||
project.version = '5.4'
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
@@ -8,8 +8,8 @@ jar {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.checkerframework:checker-qual:3.49.3'
|
||||
compileOnly 'org.jetbrains:annotations:26.0.2'
|
||||
compileOnly 'org.checkerframework:checker-qual:3.21.2'
|
||||
compileOnly 'org.jetbrains:annotations:23.1.0'
|
||||
}
|
||||
|
||||
// Only used occasionally for deployment - not needed for normal builds.
|
||||
@@ -24,13 +24,13 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
|
||||
options.charSet = 'UTF-8'
|
||||
options.links(
|
||||
'https://checkerframework.org/api/',
|
||||
'https://javadoc.io/static/org.jetbrains/annotations/26.0.2/'
|
||||
'https://javadoc.io/static/org.jetbrains/annotations/23.0.0/'
|
||||
)
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
options.addStringOption('-since', '5.0,5.1,5.2,5.3,5.4,5.5')
|
||||
|
||||
if (JavaVersion.current() > JavaVersion.VERSION_1_8) {
|
||||
options.links.add('https://docs.oracle.com/en/java/javase/21/docs/api/')
|
||||
options.links.add('https://docs.oracle.com/en/java/javase/11/docs/api/')
|
||||
} else {
|
||||
options.links.add('https://docs.oracle.com/javase/8/docs/api/')
|
||||
}
|
||||
@@ -63,7 +63,7 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
|
||||
|
||||
pom {
|
||||
name = 'LuckPerms API'
|
||||
description = 'A permissions manager for Minecraft servers.'
|
||||
description = 'A permissions plugin for Minecraft servers.'
|
||||
url = 'https://luckperms.net'
|
||||
|
||||
licenses {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<p>
|
||||
LuckPerms is a permissions manager for Minecraft servers. It allows server admins to control what
|
||||
LuckPerms is a permissions plugin for Minecraft servers. It allows server admins to control what
|
||||
features players can use by creating groups and assigning permissions.
|
||||
</p>
|
||||
<h4>Useful Links</h4>
|
||||
|
||||
@@ -79,8 +79,7 @@ public final class LuckPermsProvider {
|
||||
" a) the LuckPerms plugin is not installed or it failed to enable\n" +
|
||||
" b) the plugin in the stacktrace does not declare a dependency on LuckPerms\n" +
|
||||
" c) the plugin in the stacktrace is retrieving the API before the plugin 'enable' phase\n" +
|
||||
" (call the #get method in onEnable, not the constructor!)\n" +
|
||||
" d) the plugin in the stacktrace is incorrectly 'shading' the LuckPerms API into its jar\n";
|
||||
" (call the #get method in onEnable, not the constructor!)\n";
|
||||
|
||||
NotLoadedException() {
|
||||
super(MESSAGE);
|
||||
|
||||
@@ -63,7 +63,6 @@ public interface DisplayNameNode extends ScopedNode<DisplayNameNode, DisplayName
|
||||
*
|
||||
* @param displayName the display name to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code displayName} is empty
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String displayName) {
|
||||
return builder().displayName(displayName);
|
||||
|
||||
@@ -67,7 +67,6 @@ public interface InheritanceNode extends ScopedNode<InheritanceNode, Inheritance
|
||||
*
|
||||
* @param group the group to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code group} is not a valid group name
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String group) {
|
||||
return builder().group(group);
|
||||
|
||||
@@ -71,7 +71,6 @@ public interface MetaNode extends ScopedNode<MetaNode, MetaNode.Builder> {
|
||||
* @param key the meta key to set
|
||||
* @param value the meta value to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code key} is empty
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String key, @NonNull String value) {
|
||||
return builder().key(key).value(value);
|
||||
|
||||
@@ -88,7 +88,6 @@ public interface PermissionNode extends ScopedNode<PermissionNode, PermissionNod
|
||||
*
|
||||
* @param permission the permission to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code permission} is empty
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String permission) {
|
||||
return builder().permission(permission);
|
||||
|
||||
@@ -75,7 +75,6 @@ public interface RegexPermissionNode extends ScopedNode<RegexPermissionNode, Reg
|
||||
*
|
||||
* @param pattern the pattern to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code pattern} is empty
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String pattern) {
|
||||
return builder().pattern(pattern);
|
||||
|
||||
@@ -76,7 +76,6 @@ public interface Platform {
|
||||
NUKKIT("Nukkit"),
|
||||
VELOCITY("Velocity"),
|
||||
FABRIC("Fabric"),
|
||||
NEOFORGE("NeoForge"),
|
||||
FORGE("Forge"),
|
||||
STANDALONE("Standalone");
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public interface DataTypeFilterFunction {
|
||||
|
||||
/**
|
||||
* Creates a {@link DataTypeFilterFunction} that always returns the given
|
||||
* {@code predicate} (commonly one of the values in {@link DataTypeFilter}).
|
||||
* {@code predicate}.
|
||||
*
|
||||
* @param predicate the predicate
|
||||
* @return the data type filter function
|
||||
|
||||
+2
-2
@@ -13,7 +13,7 @@ subprojects {
|
||||
apply plugin: 'org.cadixdev.licenser'
|
||||
|
||||
group = 'me.lucko.luckperms'
|
||||
version = '5.5-SNAPSHOT'
|
||||
version = '5.4-SNAPSHOT'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
@@ -52,7 +52,7 @@ subprojects {
|
||||
}
|
||||
|
||||
project.ext.majorVersion = '5'
|
||||
project.ext.minorVersion = '5'
|
||||
project.ext.minorVersion = '4'
|
||||
project.ext.patchVersion = determinePatchVersion()
|
||||
project.ext.apiVersion = project.ext.majorVersion + '.' + project.ext.minorVersion
|
||||
project.ext.fullVersion = project.ext.apiVersion + '.' + project.ext.patchVersion
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ dependencies {
|
||||
compileOnly project(':common:loader-utils')
|
||||
|
||||
compileOnly 'com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT'
|
||||
compileOnly('net.kyori:adventure-platform-bukkit:4.4.0') {
|
||||
compileOnly('net.kyori:adventure-platform-bukkit:4.3.3') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'adventure-nbt')
|
||||
|
||||
@@ -25,46 +25,85 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.context;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.LuckPermsPermissible;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.PermissibleInjector;
|
||||
import me.lucko.luckperms.common.context.manager.DetachedContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.cache.LoadingMap;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.manager.ContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import net.luckperms.api.query.OptionKey;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BukkitContextManager extends DetachedContextManager<Player, Player> {
|
||||
public class BukkitContextManager extends ContextManager<Player, Player> {
|
||||
|
||||
public static final OptionKey<Boolean> OP_OPTION = OptionKey.of("op", Boolean.class);
|
||||
|
||||
// cache the creation of ContextsCache instances for online players with no expiry
|
||||
private final LoadingMap<Player, QueryOptionsCache<Player>> onlineSubjectCaches = LoadingMap.of(key -> new QueryOptionsCache<>(key, this));
|
||||
|
||||
// cache the creation of ContextsCache instances for offline players with a 1m expiry
|
||||
private final LoadingCache<Player, QueryOptionsCache<Player>> offlineSubjectCaches = CaffeineFactory.newBuilder()
|
||||
.expireAfterAccess(1, TimeUnit.MINUTES)
|
||||
.build(key -> {
|
||||
QueryOptionsCache<Player> cache = this.onlineSubjectCaches.getIfPresent(key);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
return new QueryOptionsCache<>(key, this);
|
||||
});
|
||||
|
||||
public BukkitContextManager(LPBukkitPlugin plugin) {
|
||||
super(plugin, Player.class, Player.class);
|
||||
}
|
||||
|
||||
public void onPlayerQuit(Player player) {
|
||||
this.onlineSubjectCaches.remove(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId(Player player) {
|
||||
return player.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable QueryOptionsSupplier getQueryOptionsSupplier(Player subject) {
|
||||
Objects.requireNonNull(subject, "subject");
|
||||
LuckPermsPermissible permissible = PermissibleInjector.get(subject);
|
||||
if (permissible != null) {
|
||||
return permissible.getQueryOptionsSupplier();
|
||||
public QueryOptionsCache<Player> getCacheFor(Player subject) {
|
||||
if (subject == null) {
|
||||
throw new NullPointerException("subject");
|
||||
}
|
||||
|
||||
if (subject.isOnline()) {
|
||||
return this.onlineSubjectCaches.get(subject);
|
||||
} else {
|
||||
return this.offlineSubjectCaches.get(subject);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeQueryOptions(Player subject, QueryOptions.Builder builder) {
|
||||
if (subject.isOp()) {
|
||||
builder.option(OP_OPTION, true);
|
||||
protected void invalidateCache(Player subject) {
|
||||
QueryOptionsCache<Player> cache = this.onlineSubjectCaches.getIfPresent(subject);
|
||||
if (cache != null) {
|
||||
cache.invalidate();
|
||||
}
|
||||
|
||||
cache = this.offlineSubjectCaches.getIfPresent(subject);
|
||||
if (cache != null) {
|
||||
cache.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions formQueryOptions(Player subject, ImmutableContextSet contextSet) {
|
||||
QueryOptions.Builder queryOptions = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder();
|
||||
if (subject.isOp()) {
|
||||
queryOptions.option(OP_OPTION, true);
|
||||
}
|
||||
|
||||
return queryOptions.context(contextSet).build();
|
||||
}
|
||||
}
|
||||
+9
-11
@@ -32,7 +32,7 @@ import me.lucko.luckperms.bukkit.calculator.OpProcessor;
|
||||
import me.lucko.luckperms.bukkit.calculator.PermissionMapProcessor;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
@@ -68,7 +68,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* "Hot" method calls, (namely #hasPermission) are significantly faster than the base implementation.
|
||||
*
|
||||
* This class is **thread safe**. This means that when LuckPerms is installed on the server,
|
||||
* it is safe to call Player#hasPermission asynchronously.
|
||||
* is is safe to call Player#hasPermission asynchronously.
|
||||
*/
|
||||
public class LuckPermsPermissible extends PermissibleBase {
|
||||
|
||||
@@ -93,7 +93,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
// caches context lookups for the player
|
||||
private final QueryOptionsSupplier queryOptionsSupplier;
|
||||
private final QueryOptionsCache<Player> queryOptionsSupplier;
|
||||
|
||||
// the players previous permissible. (the one they had before this one was injected)
|
||||
private PermissibleBase oldPermissible = null;
|
||||
@@ -110,7 +110,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
this.user = Objects.requireNonNull(user, "user");
|
||||
this.player = Objects.requireNonNull(player, "player");
|
||||
this.plugin = Objects.requireNonNull(plugin, "plugin");
|
||||
this.queryOptionsSupplier = plugin.getContextManager().createQueryOptionsSupplier(player);
|
||||
this.queryOptionsSupplier = plugin.getContextManager().getCacheFor(player);
|
||||
|
||||
injectFakeAttachmentsList();
|
||||
}
|
||||
@@ -293,7 +293,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
// the query options cache when op status changes.
|
||||
// (#invalidate is a fast call)
|
||||
if (this.queryOptionsSupplier != null) { // this method is called by the super class constructor, before this class has fully initialised
|
||||
this.queryOptionsSupplier.invalidateCache();
|
||||
this.queryOptionsSupplier.invalidate();
|
||||
}
|
||||
|
||||
// but we don't need to do anything else in this method, unlike the CB impl.
|
||||
@@ -316,10 +316,6 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
public QueryOptionsSupplier getQueryOptionsSupplier() {
|
||||
return this.queryOptionsSupplier;
|
||||
}
|
||||
|
||||
PermissibleBase getOldPermissible() {
|
||||
return this.oldPermissible;
|
||||
}
|
||||
@@ -413,7 +409,9 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
@Override public PermissionAttachment remove(int index) { throw new UnsupportedOperationException(); }
|
||||
@Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
|
||||
@Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
|
||||
@Override public @NonNull ListIterator<PermissionAttachment> listIterator(int index) { throw new UnsupportedOperationException(); }
|
||||
@Override public @NonNull List<PermissionAttachment> subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); }
|
||||
@Override
|
||||
public @NonNull ListIterator<PermissionAttachment> listIterator(int index) { throw new UnsupportedOperationException(); }
|
||||
@Override
|
||||
public @NonNull List<PermissionAttachment> subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); }
|
||||
}
|
||||
}
|
||||
-14
@@ -30,7 +30,6 @@ import me.lucko.luckperms.common.plugin.logging.PluginLogger;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
@@ -162,19 +161,6 @@ public final class PermissibleInjector {
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable LuckPermsPermissible get(Player player) {
|
||||
PermissibleBase permissibleBase;
|
||||
try {
|
||||
permissibleBase = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
|
||||
} catch (IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
if (permissibleBase instanceof LuckPermsPermissible) {
|
||||
return (LuckPermsPermissible) permissibleBase;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void checkInjected(Player player, PluginLogger logger) {
|
||||
PermissibleBase permissibleBase;
|
||||
try {
|
||||
|
||||
@@ -253,6 +253,9 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
player.setOp(false);
|
||||
}
|
||||
|
||||
// remove their contexts cache
|
||||
this.plugin.getContextManager().onPlayerQuit(player);
|
||||
}, 1L);
|
||||
}
|
||||
|
||||
|
||||
+1
-19
@@ -36,26 +36,12 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.event.server.RemoteServerCommandEvent;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BukkitPlatformListener implements Listener {
|
||||
private static final Pattern OP_COMMAND_PATTERN = Pattern.compile("^/?(\\w+:)?(deop|op)( .*)?$", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final boolean PLUGIN_DESCRIPTION_FILE_PROVIDES_SUPPORTED;
|
||||
|
||||
static {
|
||||
boolean supported = false;
|
||||
try {
|
||||
PluginDescriptionFile.class.getMethod("getProvides");
|
||||
supported = true;
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
PLUGIN_DESCRIPTION_FILE_PROVIDES_SUPPORTED = supported;
|
||||
}
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public BukkitPlatformListener(LPBukkitPlugin plugin) {
|
||||
@@ -94,11 +80,7 @@ public class BukkitPlatformListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPluginEnable(PluginEnableEvent e) {
|
||||
Plugin p = e.getPlugin();
|
||||
boolean shouldHook = p.getName().equalsIgnoreCase("Vault") ||
|
||||
(PLUGIN_DESCRIPTION_FILE_PROVIDES_SUPPORTED && p.getDescription().getProvides().contains("Vault"));
|
||||
|
||||
if (shouldHook) {
|
||||
if (e.getPlugin().getName().equalsIgnoreCase("Vault")) {
|
||||
this.plugin.tryVaultHook(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,33 +719,3 @@ register-command-list-data: true
|
||||
# If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands.
|
||||
# See here for more info: https://minecraft.wiki/w/Target_selectors
|
||||
resolve-command-selectors: false
|
||||
|
||||
# If the plugin should run in "read-only" mode for commands.
|
||||
#
|
||||
# In this mode, players or the console will only be able to execute commands that read or view
|
||||
# data, and will not be able to execute any LP commands that modify data.
|
||||
#
|
||||
# If enabling read-only mode for just players, be aware that some other plugins may allow players
|
||||
# to execute commands as the console, allowing them to run LP commands indirectly.
|
||||
#
|
||||
# Note: This does not affect interactions with LuckPerms via the API.
|
||||
commands-read-only-mode:
|
||||
players: false
|
||||
console: false
|
||||
|
||||
# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being
|
||||
# executed. In a sense this is a more extreme version of read-only mode (see above).
|
||||
#
|
||||
# LuckPerms will still act as the permission manager, but server administrators will be unable to
|
||||
# make changes via commands.
|
||||
#
|
||||
# If disabling commands just for players, be aware that some other plugins may allow players to
|
||||
# execute commands as the console, allowing them to run commands indirectly.
|
||||
#
|
||||
# If commands are disabled for both players and the console, LuckPerms will not attempt to register
|
||||
# a command with the server at all & in a sense will be invisible to both players and admins.
|
||||
#
|
||||
# Note: This does not affect interactions with LuckPerms via the API.
|
||||
disable-luckperms-commands:
|
||||
players: false
|
||||
console: false
|
||||
+1
-1
@@ -7,7 +7,7 @@ dependencies {
|
||||
compileOnly project(':common:loader-utils')
|
||||
|
||||
compileOnly 'net.md-5:bungeecord-api:1.16-R0.4'
|
||||
compileOnly('net.kyori:adventure-platform-bungeecord:4.4.0') {
|
||||
compileOnly('net.kyori:adventure-platform-bungeecord:4.3.3') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'adventure-nbt')
|
||||
|
||||
@@ -25,13 +25,25 @@
|
||||
|
||||
package me.lucko.luckperms.bungee.context;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.context.manager.SimpleContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.ContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.InlineQueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BungeeContextManager extends ContextManager<ProxiedPlayer, ProxiedPlayer> {
|
||||
|
||||
private final LoadingCache<ProxiedPlayer, QueryOptions> contextsCache = CaffeineFactory.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(this::calculate);
|
||||
|
||||
public class BungeeContextManager extends SimpleContextManager<ProxiedPlayer, ProxiedPlayer> {
|
||||
public BungeeContextManager(LPBungeePlugin plugin) {
|
||||
super(plugin, ProxiedPlayer.class, ProxiedPlayer.class);
|
||||
}
|
||||
@@ -40,4 +52,35 @@ public class BungeeContextManager extends SimpleContextManager<ProxiedPlayer, Pr
|
||||
public UUID getUniqueId(ProxiedPlayer player) {
|
||||
return player.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptionsSupplier getCacheFor(ProxiedPlayer subject) {
|
||||
if (subject == null) {
|
||||
throw new NullPointerException("subject");
|
||||
}
|
||||
|
||||
return new InlineQueryOptionsSupplier<>(subject, this.contextsCache);
|
||||
}
|
||||
|
||||
// override getContext, getQueryOptions and invalidateCache to skip the QueryOptionsSupplier
|
||||
@Override
|
||||
public ImmutableContextSet getContext(ProxiedPlayer subject) {
|
||||
return getQueryOptions(subject).context();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions(ProxiedPlayer subject) {
|
||||
return this.contextsCache.get(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invalidateCache(ProxiedPlayer subject) {
|
||||
this.contextsCache.invalidate(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions formQueryOptions(ProxiedPlayer subject, ImmutableContextSet contextSet) {
|
||||
return formQueryOptions(contextSet);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -611,33 +611,3 @@ disable-bulkupdate: false
|
||||
#
|
||||
# - When this happens, the plugin will set their primary group back to default.
|
||||
prevent-primary-group-removal: false
|
||||
|
||||
# If the plugin should run in "read-only" mode for commands.
|
||||
#
|
||||
# In this mode, players or the console will only be able to execute commands that read or view
|
||||
# data, and will not be able to execute any LP commands that modify data.
|
||||
#
|
||||
# If enabling read-only mode for just players, be aware that some other plugins may allow players
|
||||
# to execute commands as the console, allowing them to run LP commands indirectly.
|
||||
#
|
||||
# Note: This does not affect interactions with LuckPerms via the API.
|
||||
commands-read-only-mode:
|
||||
players: false
|
||||
console: false
|
||||
|
||||
# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being
|
||||
# executed. In a sense this is a more extreme version of read-only mode (see above).
|
||||
#
|
||||
# LuckPerms will still act as the permission manager, but server administrators will be unable to
|
||||
# make changes via commands.
|
||||
#
|
||||
# If disabling commands just for players, be aware that some other plugins may allow players to
|
||||
# execute commands as the console, allowing them to run commands indirectly.
|
||||
#
|
||||
# If commands are disabled for both players and the console, LuckPerms will not attempt to register
|
||||
# a command with the server at all & in a sense will be invisible to both players and admins.
|
||||
#
|
||||
# Note: This does not affect interactions with LuckPerms via the API.
|
||||
disable-luckperms-commands:
|
||||
players: false
|
||||
console: false
|
||||
+6
-9
@@ -16,11 +16,10 @@ jacocoTestReport {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'org.slf4j:slf4j-simple:1.7.36'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.1'
|
||||
testImplementation 'org.testcontainers:junit-jupiter:1.20.4'
|
||||
testImplementation "org.testcontainers:junit-jupiter:1.19.8"
|
||||
testImplementation 'org.mockito:mockito-core:5.11.0'
|
||||
testImplementation 'org.mockito:mockito-junit-jupiter:5.11.0'
|
||||
testImplementation 'com.h2database:h2:2.1.214'
|
||||
@@ -28,7 +27,6 @@ dependencies {
|
||||
testImplementation 'org.spongepowered:configurate-yaml:3.7.2'
|
||||
testImplementation 'org.spongepowered:configurate-hocon:3.7.2'
|
||||
testImplementation 'me.lucko.configurate:configurate-toml:3.7'
|
||||
testImplementation 'net.luckperms:rest-api-java-client:0.1-SNAPSHOT'
|
||||
|
||||
api project(':api')
|
||||
api 'org.checkerframework:checker-qual:3.12.0'
|
||||
@@ -39,29 +37,29 @@ dependencies {
|
||||
compileOnly 'org.slf4j:slf4j-api:1.7.30'
|
||||
compileOnly 'org.apache.logging.log4j:log4j-api:2.14.0'
|
||||
|
||||
api('net.kyori:adventure-api:4.21.0') {
|
||||
api('net.kyori:adventure-api:4.11.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'checker-qual')
|
||||
exclude(module: 'annotations')
|
||||
}
|
||||
|
||||
api('net.kyori:adventure-text-serializer-gson:4.21.0') {
|
||||
api('net.kyori:adventure-text-serializer-gson:4.11.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'gson')
|
||||
}
|
||||
|
||||
api('net.kyori:adventure-text-serializer-legacy:4.21.0') {
|
||||
api('net.kyori:adventure-text-serializer-legacy:4.11.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
|
||||
api('net.kyori:adventure-text-serializer-plain:4.21.0') {
|
||||
api('net.kyori:adventure-text-serializer-plain:4.11.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
|
||||
api("net.kyori:adventure-text-minimessage:4.21.0") {
|
||||
api("net.kyori:adventure-text-minimessage:4.11.0") {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
@@ -101,5 +99,4 @@ dependencies {
|
||||
compileOnly 'org.mongodb:mongodb-driver-legacy:4.5.0'
|
||||
compileOnly 'org.postgresql:postgresql:42.6.0'
|
||||
compileOnly 'org.yaml:snakeyaml:1.28'
|
||||
compileOnly 'net.luckperms:rest-api-java-client:0.1-SNAPSHOT'
|
||||
}
|
||||
+2
-2
@@ -26,8 +26,8 @@
|
||||
package me.lucko.luckperms.common.api.implementation;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.StandardStackElements;
|
||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.metastacking.StandardStackElements;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import net.luckperms.api.metastacking.DuplicateRemovalFunction;
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
|
||||
+1
-1
@@ -193,7 +193,7 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
this.cache.values().removeIf(value -> !((UsageTracked) value).usedInTheLast(2, TimeUnit.MINUTES));
|
||||
this.cache.values().removeIf(value -> ((UsageTracked) value).usedSince(TimeUnit.MINUTES.toMillis(2)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,20 +25,14 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class UsageTracked {
|
||||
|
||||
@VisibleForTesting
|
||||
protected long lastUsed = System.currentTimeMillis();
|
||||
private long lastUsed = System.currentTimeMillis();
|
||||
|
||||
public void recordUsage() {
|
||||
this.lastUsed = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean usedInTheLast(long duration, TimeUnit unit) {
|
||||
return this.lastUsed > System.currentTimeMillis() - unit.toMillis(duration);
|
||||
public boolean usedSince(long duration) {
|
||||
return this.lastUsed > System.currentTimeMillis() - duration;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.result;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public abstract class AbstractResult<T, N extends Node, S extends AbstractResult<T, N, S>> implements Result<T, N> {
|
||||
|
||||
/** The node that caused the result */
|
||||
protected final N node;
|
||||
/** A reference to another result that this one overrides */
|
||||
protected S overriddenResult;
|
||||
|
||||
public AbstractResult(N node, S overriddenResult) {
|
||||
this.node = node;
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable N node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public final @Nullable S overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public final void setOverriddenResult(S overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
}
|
||||
+22
-2
@@ -25,23 +25,30 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.result;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.WeightNode;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the result of an integer meta lookup
|
||||
*
|
||||
* @param <N> the node type
|
||||
*/
|
||||
public final class IntegerResult<N extends Node> extends AbstractResult<Integer, N, IntegerResult<N>> {
|
||||
public final class IntegerResult<N extends Node> implements Result<Integer, N> {
|
||||
|
||||
/** The result */
|
||||
private final int result;
|
||||
/** The node that caused the result */
|
||||
private final N node;
|
||||
/** A reference to another result that this one overrides */
|
||||
private IntegerResult<N> overriddenResult;
|
||||
|
||||
public IntegerResult(int result, N node, IntegerResult<N> overriddenResult) {
|
||||
super(node, overriddenResult);
|
||||
this.result = result;
|
||||
this.node = node;
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,6 +73,19 @@ public final class IntegerResult<N extends Node> extends AbstractResult<Integer,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable N node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public @Nullable IntegerResult<N> overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public void setOverriddenResult(IntegerResult<N> overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return this == NULL_RESULT;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.result;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
@@ -35,14 +36,19 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*
|
||||
* @param <N> the node type
|
||||
*/
|
||||
public final class StringResult<N extends Node> extends AbstractResult<String, N, StringResult<N>> {
|
||||
public final class StringResult<N extends Node> implements Result<String, N> {
|
||||
|
||||
/** The result, nullable */
|
||||
private final String result;
|
||||
/** The node that caused the result */
|
||||
private final N node;
|
||||
/** A reference to another result that this one overrides */
|
||||
private StringResult<N> overriddenResult;
|
||||
|
||||
public StringResult(String result, N node, StringResult<N> overriddenResult) {
|
||||
super(node, overriddenResult);
|
||||
this.result = result;
|
||||
this.node = node;
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,6 +56,19 @@ public final class StringResult<N extends Node> extends AbstractResult<String, N
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable N node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public @Nullable StringResult<N> overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public void setOverriddenResult(StringResult<N> overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
public StringResult<N> copy() {
|
||||
return new StringResult<>(this.result, this.node, this.overriddenResult);
|
||||
}
|
||||
|
||||
+20
-2
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.cacheddata.result;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
@@ -35,16 +36,20 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
/**
|
||||
* Represents the result of a {@link PermissionCalculator} lookup.
|
||||
*/
|
||||
public final class TristateResult extends AbstractResult<Tristate, Node, TristateResult> {
|
||||
public final class TristateResult implements Result<Tristate, Node> {
|
||||
|
||||
/** The result */
|
||||
private final Tristate result;
|
||||
/** The node that caused the result */
|
||||
private final Node node;
|
||||
/** The permission processor that provided the result */
|
||||
private final Class<? extends PermissionProcessor> processorClass;
|
||||
/** A reference to another result that this one overrides */
|
||||
private TristateResult overriddenResult;
|
||||
|
||||
private TristateResult(Tristate result, Node node, Class<? extends PermissionProcessor> processorClass) {
|
||||
super(node, null);
|
||||
this.result = result;
|
||||
this.node = node;
|
||||
this.processorClass = processorClass;
|
||||
}
|
||||
|
||||
@@ -53,6 +58,11 @@ public final class TristateResult extends AbstractResult<Tristate, Node, Tristat
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Node node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public @Nullable Class<? extends PermissionProcessor> processorClass() {
|
||||
return this.processorClass;
|
||||
}
|
||||
@@ -69,6 +79,14 @@ public final class TristateResult extends AbstractResult<Tristate, Node, Tristat
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable TristateResult overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public void setOverriddenResult(TristateResult overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TristateResult(" +
|
||||
|
||||
@@ -79,7 +79,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -102,7 +101,7 @@ public class CommandManager {
|
||||
.build()
|
||||
);
|
||||
private final AtomicBoolean executingCommand = new AtomicBoolean(false);
|
||||
private final Set<UUID> playerRateLimit = ExpiringSet.newExpiringSet(500, TimeUnit.MILLISECONDS);
|
||||
private final ExpiringSet<UUID> playerRateLimit = new ExpiringSet<>(500, TimeUnit.MILLISECONDS);
|
||||
private final TabCompletions tabCompletions;
|
||||
private final Map<String, Command<?>> mainCommands;
|
||||
|
||||
@@ -160,15 +159,6 @@ public class CommandManager {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
boolean commandsDisabled = sender.isConsole()
|
||||
? this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_CONSOLE)
|
||||
: this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_PLAYERS);
|
||||
|
||||
if (commandsDisabled) {
|
||||
Message.COMMANDS_DISABLED.send(sender);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
SchedulerAdapter scheduler = this.plugin.getBootstrap().getScheduler();
|
||||
List<String> argsCopy = new ArrayList<>(args);
|
||||
|
||||
@@ -295,14 +285,6 @@ public class CommandManager {
|
||||
}
|
||||
|
||||
public List<String> tabCompleteCommand(Sender sender, List<String> arguments) {
|
||||
boolean commandsDisabled = sender.isConsole()
|
||||
? this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_CONSOLE)
|
||||
: this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_PLAYERS);
|
||||
|
||||
if (commandsDisabled) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
applyConvenienceAliases(arguments, false);
|
||||
|
||||
final List<Command<?>> mains = this.mainCommands.values().stream()
|
||||
|
||||
+1
-2
@@ -31,7 +31,6 @@ import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
@@ -67,7 +66,7 @@ public abstract class ChildCommand<T> extends Command<T> {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
builder.append(Component.text(" - ", NamedTextColor.DARK_AQUA))
|
||||
.append(Component.join(JoinConfiguration.separator(Component.space()), argUsages))
|
||||
.append(Component.join(Component.space(), argUsages))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -35,7 +35,6 @@ import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
@@ -115,7 +114,7 @@ public abstract class GenericChildCommand {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
builder.append(Component.text(" - ", NamedTextColor.DARK_AQUA))
|
||||
.append(Component.join(JoinConfiguration.separator(Component.space()), argUsages))
|
||||
.append(Component.join(Component.space(), argUsages))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -33,7 +33,6 @@ import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
@@ -71,7 +70,7 @@ public abstract class SingleCommand extends Command<Void> {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
builder.append(Component.text(" - ", NamedTextColor.DARK_AQUA))
|
||||
.append(Component.join(JoinConfiguration.separator(Component.space()), argUsages))
|
||||
.append(Component.join(Component.space(), argUsages))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+131
-137
@@ -32,143 +32,143 @@ import me.lucko.luckperms.common.sender.Sender;
|
||||
*/
|
||||
public enum CommandPermission {
|
||||
|
||||
SYNC("sync", Type.NONE, true),
|
||||
INFO("info", Type.NONE, true),
|
||||
EDITOR("editor", Type.NONE, true),
|
||||
VERBOSE("verbose", Type.NONE, true),
|
||||
VERBOSE_COMMAND_OTHERS("verbose.command.others", Type.NONE, false),
|
||||
TREE("tree", Type.NONE, true),
|
||||
SEARCH("search", Type.NONE, true),
|
||||
IMPORT("import", Type.NONE, false),
|
||||
EXPORT("export", Type.NONE, true),
|
||||
RELOAD_CONFIG("reloadconfig", Type.NONE, true),
|
||||
BULK_UPDATE("bulkupdate", Type.NONE, false),
|
||||
APPLY_EDITS("applyedits", Type.NONE, false),
|
||||
TRUST_EDITOR("trusteditor", Type.NONE, false),
|
||||
TRANSLATIONS("translations", Type.NONE, true),
|
||||
SYNC("sync", Type.NONE),
|
||||
INFO("info", Type.NONE),
|
||||
EDITOR("editor", Type.NONE),
|
||||
VERBOSE("verbose", Type.NONE),
|
||||
VERBOSE_COMMAND_OTHERS("verbose.command.others", Type.NONE),
|
||||
TREE("tree", Type.NONE),
|
||||
SEARCH("search", Type.NONE),
|
||||
IMPORT("import", Type.NONE),
|
||||
EXPORT("export", Type.NONE),
|
||||
RELOAD_CONFIG("reloadconfig", Type.NONE),
|
||||
BULK_UPDATE("bulkupdate", Type.NONE),
|
||||
APPLY_EDITS("applyedits", Type.NONE),
|
||||
TRUST_EDITOR("trusteditor", Type.NONE),
|
||||
TRANSLATIONS("translations", Type.NONE),
|
||||
|
||||
CREATE_GROUP("creategroup", Type.NONE, false),
|
||||
DELETE_GROUP("deletegroup", Type.NONE, false),
|
||||
LIST_GROUPS("listgroups", Type.NONE, true),
|
||||
CREATE_GROUP("creategroup", Type.NONE),
|
||||
DELETE_GROUP("deletegroup", Type.NONE),
|
||||
LIST_GROUPS("listgroups", Type.NONE),
|
||||
|
||||
CREATE_TRACK("createtrack", Type.NONE, false),
|
||||
DELETE_TRACK("deletetrack", Type.NONE, false),
|
||||
LIST_TRACKS("listtracks", Type.NONE, true),
|
||||
CREATE_TRACK("createtrack", Type.NONE),
|
||||
DELETE_TRACK("deletetrack", Type.NONE),
|
||||
LIST_TRACKS("listtracks", Type.NONE),
|
||||
|
||||
USER_INFO("info", Type.USER, true),
|
||||
USER_PERM_INFO("permission.info", Type.USER, true),
|
||||
USER_PERM_SET("permission.set", Type.USER, false),
|
||||
USER_PERM_UNSET("permission.unset", Type.USER, false),
|
||||
USER_PERM_SET_TEMP("permission.settemp", Type.USER, false),
|
||||
USER_PERM_UNSET_TEMP("permission.unsettemp", Type.USER, false),
|
||||
USER_PERM_CHECK("permission.check", Type.USER, true),
|
||||
USER_PERM_CLEAR("permission.clear", Type.USER, false),
|
||||
USER_PARENT_INFO("parent.info", Type.USER, true),
|
||||
USER_PARENT_SET("parent.set", Type.USER, false),
|
||||
USER_PARENT_SET_TRACK("parent.settrack", Type.USER, false),
|
||||
USER_PARENT_ADD("parent.add", Type.USER, false),
|
||||
USER_PARENT_REMOVE("parent.remove", Type.USER, false),
|
||||
USER_PARENT_ADD_TEMP("parent.addtemp", Type.USER, false),
|
||||
USER_PARENT_REMOVE_TEMP("parent.removetemp", Type.USER, false),
|
||||
USER_PARENT_CLEAR("parent.clear", Type.USER, false),
|
||||
USER_PARENT_CLEAR_TRACK("parent.cleartrack", Type.USER, false),
|
||||
USER_PARENT_SWITCHPRIMARYGROUP("parent.switchprimarygroup", Type.USER, false),
|
||||
USER_META_INFO("meta.info", Type.USER, true),
|
||||
USER_META_SET("meta.set", Type.USER, false),
|
||||
USER_META_UNSET("meta.unset", Type.USER, false),
|
||||
USER_META_SET_TEMP("meta.settemp", Type.USER, false),
|
||||
USER_META_UNSET_TEMP("meta.unsettemp", Type.USER, false),
|
||||
USER_META_ADD_PREFIX("meta.addprefix", Type.USER, false),
|
||||
USER_META_ADD_SUFFIX("meta.addsuffix", Type.USER, false),
|
||||
USER_META_SET_PREFIX("meta.setprefix", Type.USER, false),
|
||||
USER_META_SET_SUFFIX("meta.setsuffix", Type.USER, false),
|
||||
USER_META_REMOVE_PREFIX("meta.removeprefix", Type.USER, false),
|
||||
USER_META_REMOVE_SUFFIX("meta.removesuffix", Type.USER, false),
|
||||
USER_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.USER, false),
|
||||
USER_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.USER, false),
|
||||
USER_META_SET_TEMP_PREFIX("meta.settempprefix", Type.USER, false),
|
||||
USER_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.USER, false),
|
||||
USER_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.USER, false),
|
||||
USER_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.USER, false),
|
||||
USER_META_CLEAR("meta.clear", Type.USER, false),
|
||||
USER_EDITOR("editor", Type.USER, true),
|
||||
USER_SHOW_TRACKS("showtracks", Type.USER, true),
|
||||
USER_PROMOTE("promote", Type.USER, false),
|
||||
USER_DEMOTE("demote", Type.USER, false),
|
||||
USER_CLEAR("clear", Type.USER, false),
|
||||
USER_CLONE("clone", Type.USER, false),
|
||||
USER_INFO("info", Type.USER),
|
||||
USER_PERM_INFO("permission.info", Type.USER),
|
||||
USER_PERM_SET("permission.set", Type.USER),
|
||||
USER_PERM_UNSET("permission.unset", Type.USER),
|
||||
USER_PERM_SET_TEMP("permission.settemp", Type.USER),
|
||||
USER_PERM_UNSET_TEMP("permission.unsettemp", Type.USER),
|
||||
USER_PERM_CHECK("permission.check", Type.USER),
|
||||
USER_PERM_CLEAR("permission.clear", Type.USER),
|
||||
USER_PARENT_INFO("parent.info", Type.USER),
|
||||
USER_PARENT_SET("parent.set", Type.USER),
|
||||
USER_PARENT_SET_TRACK("parent.settrack", Type.USER),
|
||||
USER_PARENT_ADD("parent.add", Type.USER),
|
||||
USER_PARENT_REMOVE("parent.remove", Type.USER),
|
||||
USER_PARENT_ADD_TEMP("parent.addtemp", Type.USER),
|
||||
USER_PARENT_REMOVE_TEMP("parent.removetemp", Type.USER),
|
||||
USER_PARENT_CLEAR("parent.clear", Type.USER),
|
||||
USER_PARENT_CLEAR_TRACK("parent.cleartrack", Type.USER),
|
||||
USER_PARENT_SWITCHPRIMARYGROUP("parent.switchprimarygroup", Type.USER),
|
||||
USER_META_INFO("meta.info", Type.USER),
|
||||
USER_META_SET("meta.set", Type.USER),
|
||||
USER_META_UNSET("meta.unset", Type.USER),
|
||||
USER_META_SET_TEMP("meta.settemp", Type.USER),
|
||||
USER_META_UNSET_TEMP("meta.unsettemp", Type.USER),
|
||||
USER_META_ADD_PREFIX("meta.addprefix", Type.USER),
|
||||
USER_META_ADD_SUFFIX("meta.addsuffix", Type.USER),
|
||||
USER_META_SET_PREFIX("meta.setprefix", Type.USER),
|
||||
USER_META_SET_SUFFIX("meta.setsuffix", Type.USER),
|
||||
USER_META_REMOVE_PREFIX("meta.removeprefix", Type.USER),
|
||||
USER_META_REMOVE_SUFFIX("meta.removesuffix", Type.USER),
|
||||
USER_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.USER),
|
||||
USER_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.USER),
|
||||
USER_META_SET_TEMP_PREFIX("meta.settempprefix", Type.USER),
|
||||
USER_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.USER),
|
||||
USER_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.USER),
|
||||
USER_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.USER),
|
||||
USER_META_CLEAR("meta.clear", Type.USER),
|
||||
USER_EDITOR("editor", Type.USER),
|
||||
USER_SHOW_TRACKS("showtracks", Type.USER),
|
||||
USER_PROMOTE("promote", Type.USER),
|
||||
USER_DEMOTE("demote", Type.USER),
|
||||
USER_CLEAR("clear", Type.USER),
|
||||
USER_CLONE("clone", Type.USER),
|
||||
|
||||
GROUP_INFO("info", Type.GROUP, true),
|
||||
GROUP_PERM_INFO("permission.info", Type.GROUP, true),
|
||||
GROUP_PERM_SET("permission.set", Type.GROUP, false),
|
||||
GROUP_PERM_UNSET("permission.unset", Type.GROUP, false),
|
||||
GROUP_PERM_SET_TEMP("permission.settemp", Type.GROUP, false),
|
||||
GROUP_PERM_UNSET_TEMP("permission.unsettemp", Type.GROUP, false),
|
||||
GROUP_PERM_CHECK("permission.check", Type.GROUP, true),
|
||||
GROUP_PERM_CLEAR("permission.clear", Type.GROUP, false),
|
||||
GROUP_PARENT_INFO("parent.info", Type.GROUP, true),
|
||||
GROUP_PARENT_SET("parent.set", Type.GROUP, false),
|
||||
GROUP_PARENT_SET_TRACK("parent.settrack", Type.GROUP, false),
|
||||
GROUP_PARENT_ADD("parent.add", Type.GROUP, false),
|
||||
GROUP_PARENT_REMOVE("parent.remove", Type.GROUP, false),
|
||||
GROUP_PARENT_ADD_TEMP("parent.addtemp", Type.GROUP, false),
|
||||
GROUP_PARENT_REMOVE_TEMP("parent.removetemp", Type.GROUP, false),
|
||||
GROUP_PARENT_CLEAR("parent.clear", Type.GROUP, false),
|
||||
GROUP_PARENT_CLEAR_TRACK("parent.cleartrack", Type.GROUP, false),
|
||||
GROUP_META_INFO("meta.info", Type.GROUP, true),
|
||||
GROUP_META_SET("meta.set", Type.GROUP, false),
|
||||
GROUP_META_UNSET("meta.unset", Type.GROUP, false),
|
||||
GROUP_META_SET_TEMP("meta.settemp", Type.GROUP, false),
|
||||
GROUP_META_UNSET_TEMP("meta.unsettemp", Type.GROUP, false),
|
||||
GROUP_META_ADD_PREFIX("meta.addprefix", Type.GROUP, false),
|
||||
GROUP_META_ADD_SUFFIX("meta.addsuffix", Type.GROUP, false),
|
||||
GROUP_META_SET_PREFIX("meta.setprefix", Type.GROUP, false),
|
||||
GROUP_META_SET_SUFFIX("meta.setsuffix", Type.GROUP, false),
|
||||
GROUP_META_REMOVE_PREFIX("meta.removeprefix", Type.GROUP, false),
|
||||
GROUP_META_REMOVE_SUFFIX("meta.removesuffix", Type.GROUP, false),
|
||||
GROUP_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.GROUP, false),
|
||||
GROUP_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.GROUP, false),
|
||||
GROUP_META_SET_TEMP_PREFIX("meta.settempprefix", Type.GROUP, false),
|
||||
GROUP_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.GROUP, false),
|
||||
GROUP_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.GROUP, false),
|
||||
GROUP_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.GROUP, false),
|
||||
GROUP_META_CLEAR("meta.clear", Type.GROUP, false),
|
||||
GROUP_EDITOR("editor", Type.GROUP, true),
|
||||
GROUP_LIST_MEMBERS("listmembers", Type.GROUP, true),
|
||||
GROUP_SHOW_TRACKS("showtracks", Type.GROUP, true),
|
||||
GROUP_SET_WEIGHT("setweight", Type.GROUP, false),
|
||||
GROUP_SET_DISPLAY_NAME("setdisplayname", Type.GROUP, false),
|
||||
GROUP_CLEAR("clear", Type.GROUP, false),
|
||||
GROUP_RENAME("rename", Type.GROUP, false),
|
||||
GROUP_CLONE("clone", Type.GROUP, false),
|
||||
GROUP_INFO("info", Type.GROUP),
|
||||
GROUP_PERM_INFO("permission.info", Type.GROUP),
|
||||
GROUP_PERM_SET("permission.set", Type.GROUP),
|
||||
GROUP_PERM_UNSET("permission.unset", Type.GROUP),
|
||||
GROUP_PERM_SET_TEMP("permission.settemp", Type.GROUP),
|
||||
GROUP_PERM_UNSET_TEMP("permission.unsettemp", Type.GROUP),
|
||||
GROUP_PERM_CHECK("permission.check", Type.GROUP),
|
||||
GROUP_PERM_CLEAR("permission.clear", Type.GROUP),
|
||||
GROUP_PARENT_INFO("parent.info", Type.GROUP),
|
||||
GROUP_PARENT_SET("parent.set", Type.GROUP),
|
||||
GROUP_PARENT_SET_TRACK("parent.settrack", Type.GROUP),
|
||||
GROUP_PARENT_ADD("parent.add", Type.GROUP),
|
||||
GROUP_PARENT_REMOVE("parent.remove", Type.GROUP),
|
||||
GROUP_PARENT_ADD_TEMP("parent.addtemp", Type.GROUP),
|
||||
GROUP_PARENT_REMOVE_TEMP("parent.removetemp", Type.GROUP),
|
||||
GROUP_PARENT_CLEAR("parent.clear", Type.GROUP),
|
||||
GROUP_PARENT_CLEAR_TRACK("parent.cleartrack", Type.GROUP),
|
||||
GROUP_META_INFO("meta.info", Type.GROUP),
|
||||
GROUP_META_SET("meta.set", Type.GROUP),
|
||||
GROUP_META_UNSET("meta.unset", Type.GROUP),
|
||||
GROUP_META_SET_TEMP("meta.settemp", Type.GROUP),
|
||||
GROUP_META_UNSET_TEMP("meta.unsettemp", Type.GROUP),
|
||||
GROUP_META_ADD_PREFIX("meta.addprefix", Type.GROUP),
|
||||
GROUP_META_ADD_SUFFIX("meta.addsuffix", Type.GROUP),
|
||||
GROUP_META_SET_PREFIX("meta.setprefix", Type.GROUP),
|
||||
GROUP_META_SET_SUFFIX("meta.setsuffix", Type.GROUP),
|
||||
GROUP_META_REMOVE_PREFIX("meta.removeprefix", Type.GROUP),
|
||||
GROUP_META_REMOVE_SUFFIX("meta.removesuffix", Type.GROUP),
|
||||
GROUP_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.GROUP),
|
||||
GROUP_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.GROUP),
|
||||
GROUP_META_SET_TEMP_PREFIX("meta.settempprefix", Type.GROUP),
|
||||
GROUP_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.GROUP),
|
||||
GROUP_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.GROUP),
|
||||
GROUP_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.GROUP),
|
||||
GROUP_META_CLEAR("meta.clear", Type.GROUP),
|
||||
GROUP_EDITOR("editor", Type.GROUP),
|
||||
GROUP_LIST_MEMBERS("listmembers", Type.GROUP),
|
||||
GROUP_SHOW_TRACKS("showtracks", Type.GROUP),
|
||||
GROUP_SET_WEIGHT("setweight", Type.GROUP),
|
||||
GROUP_SET_DISPLAY_NAME("setdisplayname", Type.GROUP),
|
||||
GROUP_CLEAR("clear", Type.GROUP),
|
||||
GROUP_RENAME("rename", Type.GROUP),
|
||||
GROUP_CLONE("clone", Type.GROUP),
|
||||
|
||||
TRACK_INFO("info", Type.TRACK, true),
|
||||
TRACK_EDITOR("editor", Type.TRACK, true),
|
||||
TRACK_APPEND("append", Type.TRACK, false),
|
||||
TRACK_INSERT("insert", Type.TRACK, false),
|
||||
TRACK_REMOVE("remove", Type.TRACK, false),
|
||||
TRACK_CLEAR("clear", Type.TRACK, false),
|
||||
TRACK_RENAME("rename", Type.TRACK, false),
|
||||
TRACK_CLONE("clone", Type.TRACK, false),
|
||||
TRACK_INFO("info", Type.TRACK),
|
||||
TRACK_EDITOR("editor", Type.TRACK),
|
||||
TRACK_APPEND("append", Type.TRACK),
|
||||
TRACK_INSERT("insert", Type.TRACK),
|
||||
TRACK_REMOVE("remove", Type.TRACK),
|
||||
TRACK_CLEAR("clear", Type.TRACK),
|
||||
TRACK_RENAME("rename", Type.TRACK),
|
||||
TRACK_CLONE("clone", Type.TRACK),
|
||||
|
||||
LOG_RECENT("recent", Type.LOG, true),
|
||||
LOG_USER_HISTORY("userhistory", Type.LOG, true),
|
||||
LOG_GROUP_HISTORY("grouphistory", Type.LOG, true),
|
||||
LOG_TRACK_HISTORY("trackhistory", Type.LOG, true),
|
||||
LOG_SEARCH("search", Type.LOG, true),
|
||||
LOG_NOTIFY("notify", Type.LOG, true),
|
||||
LOG_RECENT("recent", Type.LOG),
|
||||
LOG_USER_HISTORY("userhistory", Type.LOG),
|
||||
LOG_GROUP_HISTORY("grouphistory", Type.LOG),
|
||||
LOG_TRACK_HISTORY("trackhistory", Type.LOG),
|
||||
LOG_SEARCH("search", Type.LOG),
|
||||
LOG_NOTIFY("notify", Type.LOG),
|
||||
|
||||
SPONGE_PERMISSION_INFO("permission.info", Type.SPONGE, true),
|
||||
SPONGE_PERMISSION_SET("permission.set", Type.SPONGE, false),
|
||||
SPONGE_PERMISSION_CLEAR("permission.clear", Type.SPONGE, false),
|
||||
SPONGE_PARENT_INFO("parent.info", Type.SPONGE, true),
|
||||
SPONGE_PARENT_ADD("parent.add", Type.SPONGE, false),
|
||||
SPONGE_PARENT_REMOVE("parent.remove", Type.SPONGE, false),
|
||||
SPONGE_PARENT_CLEAR("parent.clear", Type.SPONGE, false),
|
||||
SPONGE_OPTION_INFO("option.info", Type.SPONGE, true),
|
||||
SPONGE_OPTION_SET("option.set", Type.SPONGE, false),
|
||||
SPONGE_OPTION_UNSET("option.unset", Type.SPONGE, false),
|
||||
SPONGE_OPTION_CLEAR("option.clear", Type.SPONGE, false);
|
||||
SPONGE_PERMISSION_INFO("permission.info", Type.SPONGE),
|
||||
SPONGE_PERMISSION_SET("permission.set", Type.SPONGE),
|
||||
SPONGE_PERMISSION_CLEAR("permission.clear", Type.SPONGE),
|
||||
SPONGE_PARENT_INFO("parent.info", Type.SPONGE),
|
||||
SPONGE_PARENT_ADD("parent.add", Type.SPONGE),
|
||||
SPONGE_PARENT_REMOVE("parent.remove", Type.SPONGE),
|
||||
SPONGE_PARENT_CLEAR("parent.clear", Type.SPONGE),
|
||||
SPONGE_OPTION_INFO("option.info", Type.SPONGE),
|
||||
SPONGE_OPTION_SET("option.set", Type.SPONGE),
|
||||
SPONGE_OPTION_UNSET("option.unset", Type.SPONGE),
|
||||
SPONGE_OPTION_CLEAR("option.clear", Type.SPONGE);
|
||||
|
||||
public static final String ROOT = "luckperms.";
|
||||
|
||||
@@ -176,11 +176,9 @@ public enum CommandPermission {
|
||||
private final String permission;
|
||||
|
||||
private final Type type;
|
||||
private final boolean readOnly;
|
||||
|
||||
CommandPermission(String node, Type type, boolean readOnly) {
|
||||
CommandPermission(String node, Type type) {
|
||||
this.type = type;
|
||||
this.readOnly = readOnly;
|
||||
|
||||
if (type == Type.NONE) {
|
||||
this.node = node;
|
||||
@@ -207,10 +205,6 @@ public enum CommandPermission {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return this.readOnly;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
||||
NONE(null),
|
||||
|
||||
@@ -28,14 +28,14 @@ package me.lucko.luckperms.common.config;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.StandardStackElements;
|
||||
import me.lucko.luckperms.common.cacheddata.type.SimpleMetaValueSelector;
|
||||
import me.lucko.luckperms.common.config.generic.KeyedConfiguration;
|
||||
import me.lucko.luckperms.common.config.generic.key.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.generic.key.SimpleConfigKey;
|
||||
import me.lucko.luckperms.common.context.calculator.WorldNameRewriter;
|
||||
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
|
||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.metastacking.StandardStackElements;
|
||||
import me.lucko.luckperms.common.model.PrimaryGroupHolder;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsBuilderImpl;
|
||||
@@ -246,26 +246,6 @@ public final class ConfigKeys {
|
||||
*/
|
||||
public static final ConfigKey<Boolean> REQUIRE_SENDER_GROUP_MEMBERSHIP_TO_MODIFY = booleanKey("require-sender-group-membership-to-modify", false);
|
||||
|
||||
/**
|
||||
* If the plugin is in read-only mode for players
|
||||
*/
|
||||
public static final ConfigKey<Boolean> READ_ONLY_MODE_PLAYERS = booleanKey("commands-read-only-mode.players", false);
|
||||
|
||||
/**
|
||||
* If the plugin is in read-only mode for the server console
|
||||
*/
|
||||
public static final ConfigKey<Boolean> READ_ONLY_MODE_CONSOLE = booleanKey("commands-read-only-mode.console", false);
|
||||
|
||||
/**
|
||||
* If LuckPerms commands are disabled for players
|
||||
*/
|
||||
public static final ConfigKey<Boolean> DISABLE_LUCKPERMS_COMMANDS_PLAYERS = booleanKey("disable-luckperms-commands.players", false);
|
||||
|
||||
/**
|
||||
* If LuckPerms commands are disabled for the server console
|
||||
*/
|
||||
public static final ConfigKey<Boolean> DISABLE_LUCKPERMS_COMMANDS_CONSOLE = booleanKey("disable-luckperms-commands.console", false);
|
||||
|
||||
/**
|
||||
* If wildcards are being applied
|
||||
*/
|
||||
@@ -390,16 +370,16 @@ public final class ConfigKeys {
|
||||
/**
|
||||
* Creates a new prefix MetaStack element based upon the configured values.
|
||||
*/
|
||||
public static final ConfigKey<MetaStackDefinition> PREFIX_FORMATTING_OPTIONS = key(c -> {
|
||||
List<String> format = c.getStringList("meta-formatting.prefix.format", new ArrayList<>());
|
||||
public static final ConfigKey<MetaStackDefinition> PREFIX_FORMATTING_OPTIONS = key(l -> {
|
||||
List<String> format = l.getStringList("meta-formatting.prefix.format", new ArrayList<>());
|
||||
if (format.isEmpty()) {
|
||||
format.add("highest");
|
||||
}
|
||||
String startSpacer = c.getString("meta-formatting.prefix.start-spacer", "");
|
||||
String middleSpacer = c.getString("meta-formatting.prefix.middle-spacer", " ");
|
||||
String endSpacer = c.getString("meta-formatting.prefix.end-spacer", "");
|
||||
String startSpacer = l.getString("meta-formatting.prefix.start-spacer", "");
|
||||
String middleSpacer = l.getString("meta-formatting.prefix.middle-spacer", " ");
|
||||
String endSpacer = l.getString("meta-formatting.prefix.end-spacer", "");
|
||||
DuplicateRemovalFunction duplicateRemovalFunction;
|
||||
switch (c.getString("meta-formatting.prefix.duplicates", "").toLowerCase(Locale.ROOT)) {
|
||||
switch (l.getString("meta-formatting.prefix.duplicates", "").toLowerCase(Locale.ROOT)) {
|
||||
case "first-only":
|
||||
duplicateRemovalFunction = DuplicateRemovalFunction.FIRST_ONLY;
|
||||
break;
|
||||
@@ -411,22 +391,22 @@ public final class ConfigKeys {
|
||||
break;
|
||||
}
|
||||
|
||||
return new SimpleMetaStackDefinition(StandardStackElements.parseList(c.getPlugin(), format), duplicateRemovalFunction, startSpacer, middleSpacer, endSpacer);
|
||||
return new SimpleMetaStackDefinition(StandardStackElements.parseList(l.getPlugin(), format), duplicateRemovalFunction, startSpacer, middleSpacer, endSpacer);
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a new suffix MetaStack element based upon the configured values.
|
||||
*/
|
||||
public static final ConfigKey<MetaStackDefinition> SUFFIX_FORMATTING_OPTIONS = key(c -> {
|
||||
List<String> format = c.getStringList("meta-formatting.suffix.format", new ArrayList<>());
|
||||
public static final ConfigKey<MetaStackDefinition> SUFFIX_FORMATTING_OPTIONS = key(l -> {
|
||||
List<String> format = l.getStringList("meta-formatting.suffix.format", new ArrayList<>());
|
||||
if (format.isEmpty()) {
|
||||
format.add("highest");
|
||||
}
|
||||
String startSpacer = c.getString("meta-formatting.suffix.start-spacer", "");
|
||||
String middleSpacer = c.getString("meta-formatting.suffix.middle-spacer", " ");
|
||||
String endSpacer = c.getString("meta-formatting.suffix.end-spacer", "");
|
||||
String startSpacer = l.getString("meta-formatting.suffix.start-spacer", "");
|
||||
String middleSpacer = l.getString("meta-formatting.suffix.middle-spacer", " ");
|
||||
String endSpacer = l.getString("meta-formatting.suffix.end-spacer", "");
|
||||
DuplicateRemovalFunction duplicateRemovalFunction;
|
||||
switch (c.getString("meta-formatting.suffix.duplicates", "").toLowerCase(Locale.ROOT)) {
|
||||
switch (l.getString("meta-formatting.suffix.duplicates", "").toLowerCase(Locale.ROOT)) {
|
||||
case "first-only":
|
||||
duplicateRemovalFunction = DuplicateRemovalFunction.FIRST_ONLY;
|
||||
break;
|
||||
@@ -438,7 +418,7 @@ public final class ConfigKeys {
|
||||
break;
|
||||
}
|
||||
|
||||
return new SimpleMetaStackDefinition(StandardStackElements.parseList(c.getPlugin(), format), duplicateRemovalFunction, startSpacer, middleSpacer, endSpacer);
|
||||
return new SimpleMetaStackDefinition(StandardStackElements.parseList(l.getPlugin(), format), duplicateRemovalFunction, startSpacer, middleSpacer, endSpacer);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -605,16 +585,6 @@ public final class ConfigKeys {
|
||||
return c.getString("data.mongodb-connection-uri", c.getString("data.mongodb_connection_URI", ""));
|
||||
}));
|
||||
|
||||
/**
|
||||
* The REST storage URL
|
||||
*/
|
||||
public static final ConfigKey<String> REST_STORAGE_URL = notReloadable(stringKey("data.rest-url", "http://localhost:8080/"));
|
||||
|
||||
/**
|
||||
* The REST storage auth key
|
||||
*/
|
||||
public static final ConfigKey<String> REST_STORAGE_AUTH_KEY = notReloadable(stringKey("data.rest-auth-key", ""));
|
||||
|
||||
/**
|
||||
* The name of the storage method being used
|
||||
*/
|
||||
|
||||
-90
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.config.generic.adapter;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Locale;
|
||||
|
||||
public class FileSecretConfigAdapter extends StringBasedConfigurationAdapter {
|
||||
private static final String PREFIX = "luckperms_";
|
||||
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final Path directory;
|
||||
|
||||
public FileSecretConfigAdapter(LuckPermsPlugin plugin, String directory) {
|
||||
this.plugin = plugin;
|
||||
this.directory = directory == null ? null : Paths.get(directory);
|
||||
}
|
||||
|
||||
public FileSecretConfigAdapter(LuckPermsPlugin plugin) {
|
||||
this(plugin, System.getenv("LUCKPERMS_FILE_SECRET_DIRECTORY"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable String resolveValue(String path) {
|
||||
if (this.directory == null) {
|
||||
return null; // not configured
|
||||
}
|
||||
|
||||
// e.g.
|
||||
// 'server' -> luckperms_server
|
||||
// 'data.table_prefix' -> luckperms_data_table_prefix
|
||||
String key = PREFIX + path.toLowerCase(Locale.ROOT)
|
||||
.replace('-', '_')
|
||||
.replace('.', '_');
|
||||
|
||||
Path resolvedFile = this.directory.resolve(key);
|
||||
|
||||
String value;
|
||||
try {
|
||||
value = new String(Files.readAllBytes(resolvedFile), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String printableValue = ConfigKeys.shouldCensorValue(path) ? "*****" : value;
|
||||
this.plugin.getLogger().info(String.format("Resolved configuration value from file secret: %s = %s", key, printableValue));
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuckPermsPlugin getPlugin() {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
+14
-17
@@ -46,10 +46,9 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Base implementation of {@link ContextManager}.
|
||||
* Base implementation of {@link ContextManager} which caches content lookups.
|
||||
*
|
||||
* @param <S> the subject type
|
||||
* @param <P> the player type
|
||||
* @param <S> the calculator type
|
||||
*/
|
||||
public abstract class ContextManager<S, P extends S> {
|
||||
|
||||
@@ -78,10 +77,14 @@ public abstract class ContextManager<S, P extends S> {
|
||||
|
||||
public abstract UUID getUniqueId(P player);
|
||||
|
||||
public abstract QueryOptions getQueryOptions(S subject);
|
||||
public abstract QueryOptionsSupplier getCacheFor(S subject);
|
||||
|
||||
public QueryOptions getQueryOptions(S subject) {
|
||||
return getCacheFor(subject).getQueryOptions();
|
||||
}
|
||||
|
||||
public ImmutableContextSet getContext(S subject) {
|
||||
return getQueryOptions(subject).context();
|
||||
return getCacheFor(subject).getContextSet();
|
||||
}
|
||||
|
||||
public QueryOptions getStaticQueryOptions() {
|
||||
@@ -92,13 +95,11 @@ public abstract class ContextManager<S, P extends S> {
|
||||
return getStaticQueryOptions().context();
|
||||
}
|
||||
|
||||
public void customizeStaticQueryOptions(QueryOptions.Builder builder) {
|
||||
// overridden
|
||||
public QueryOptions formQueryOptions(ImmutableContextSet contextSet) {
|
||||
return this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder().context(contextSet).build();
|
||||
}
|
||||
|
||||
public void customizeQueryOptions(S subject, QueryOptions.Builder builder) {
|
||||
// overridden
|
||||
}
|
||||
public abstract QueryOptions formQueryOptions(S subject, ImmutableContextSet contextSet);
|
||||
|
||||
public void signalContextUpdate(S subject) {
|
||||
if (subject == null) {
|
||||
@@ -112,7 +113,7 @@ public abstract class ContextManager<S, P extends S> {
|
||||
this.plugin.getEventDispatcher().dispatchContextUpdate(subject);
|
||||
}
|
||||
|
||||
public abstract void invalidateCache(S subject);
|
||||
protected abstract void invalidateCache(S subject);
|
||||
|
||||
public void registerCalculator(ContextCalculator<? super S> calculator) {
|
||||
String calculatorClass = calculator.getClass().getName();
|
||||
@@ -156,9 +157,7 @@ public abstract class ContextManager<S, P extends S> {
|
||||
callContextCalculator(calculator, subject, consumer);
|
||||
}
|
||||
|
||||
QueryOptions.Builder builder = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder().context(accumulator.build());
|
||||
customizeQueryOptions(subject, builder);
|
||||
return builder.build();
|
||||
return formQueryOptions(subject, accumulator.build());
|
||||
}
|
||||
|
||||
private QueryOptions calculateStatic() {
|
||||
@@ -169,9 +168,7 @@ public abstract class ContextManager<S, P extends S> {
|
||||
callStaticContextCalculator(calculator, consumer);
|
||||
}
|
||||
|
||||
QueryOptions.Builder builder = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder().context(accumulator.build());
|
||||
customizeStaticQueryOptions(builder);
|
||||
return builder.build();
|
||||
return formQueryOptions(accumulator.build());
|
||||
}
|
||||
|
||||
public ImmutableContextSet getPotentialContexts() {
|
||||
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.context.manager;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ContextManager} which utilises 'detached' supplier caches stored alongside the subject instances.
|
||||
*/
|
||||
public abstract class DetachedContextManager<S, P extends S> extends ContextManager<S, P> {
|
||||
|
||||
private final LoadingCache<S, QueryOptions> fallbackContextsCache = CaffeineFactory.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(this::calculate);
|
||||
|
||||
protected DetachedContextManager(LuckPermsPlugin plugin, Class<S> subjectClass, Class<P> playerClass) {
|
||||
super(plugin, subjectClass, playerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions(S subject) {
|
||||
QueryOptionsSupplier supplier = getQueryOptionsSupplier(subject);
|
||||
if (supplier != null) {
|
||||
return supplier.getQueryOptions();
|
||||
}
|
||||
return this.fallbackContextsCache.get(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache(S subject) {
|
||||
QueryOptionsSupplier queryOptionsSupplier = getQueryOptionsSupplier(subject);
|
||||
if (queryOptionsSupplier != null) {
|
||||
queryOptionsSupplier.invalidateCache();
|
||||
}
|
||||
this.fallbackContextsCache.invalidate(subject);
|
||||
}
|
||||
|
||||
public QueryOptionsSupplier createQueryOptionsSupplier(S subject) {
|
||||
return new QueryOptionsCache<>(subject, this);
|
||||
}
|
||||
|
||||
public abstract @Nullable QueryOptionsSupplier getQueryOptionsSupplier(S subject);
|
||||
|
||||
}
|
||||
+11
-12
@@ -23,23 +23,22 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.neoforge;
|
||||
package me.lucko.luckperms.common.context.manager;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.scheduler.AbstractJavaScheduler;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
public final class InlineQueryOptionsSupplier<T> implements QueryOptionsSupplier {
|
||||
private final T key;
|
||||
private final LoadingCache<T, QueryOptions> cache;
|
||||
|
||||
public class NeoForgeSchedulerAdapter extends AbstractJavaScheduler {
|
||||
private final Executor sync;
|
||||
|
||||
public NeoForgeSchedulerAdapter(LPNeoForgeBootstrap bootstrap) {
|
||||
super(bootstrap);
|
||||
this.sync = r -> bootstrap.getServer().orElseThrow(() -> new IllegalStateException("Server not ready")).executeBlocking(r);
|
||||
public InlineQueryOptionsSupplier(T key, LoadingCache<T, QueryOptions> cache) {
|
||||
this.key = key;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor sync() {
|
||||
return this.sync;
|
||||
public QueryOptions getQueryOptions() {
|
||||
return this.cache.get(this.key);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-7
@@ -37,11 +37,11 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @param <T> the player type
|
||||
*/
|
||||
final class QueryOptionsCache<T> extends ExpiringCache<QueryOptions> implements QueryOptionsSupplier {
|
||||
public final class QueryOptionsCache<T> extends ExpiringCache<QueryOptions> implements QueryOptionsSupplier {
|
||||
private final T subject;
|
||||
private final ContextManager<T, ?> contextManager;
|
||||
|
||||
QueryOptionsCache(T subject, ContextManager<T, ?> contextManager) {
|
||||
public QueryOptionsCache(T subject, ContextManager<T, ?> contextManager) {
|
||||
super(50L, TimeUnit.MILLISECONDS); // expire roughly every tick
|
||||
this.subject = subject;
|
||||
this.contextManager = contextManager;
|
||||
@@ -61,9 +61,4 @@ final class QueryOptionsCache<T> extends ExpiringCache<QueryOptions> implements
|
||||
public ImmutableContextSet getContextSet() {
|
||||
return get().context();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache() {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
-2
@@ -39,6 +39,4 @@ public interface QueryOptionsSupplier {
|
||||
return getQueryOptions().context();
|
||||
}
|
||||
|
||||
void invalidateCache();
|
||||
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.context.manager;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class SimpleContextManager<S, P extends S> extends ContextManager<S, P> {
|
||||
|
||||
private final LoadingCache<S, QueryOptions> contextsCache = CaffeineFactory.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(this::calculate);
|
||||
|
||||
protected SimpleContextManager(LuckPermsPlugin plugin, Class<S> subjectClass, Class<P> playerClass) {
|
||||
super(plugin, subjectClass, playerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions(S subject) {
|
||||
return this.contextsCache.get(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache(S subject) {
|
||||
this.contextsCache.invalidate(subject);
|
||||
}
|
||||
}
|
||||
@@ -62,28 +62,28 @@ public enum Dependency {
|
||||
ADVENTURE(
|
||||
"me{}lucko",
|
||||
"adventure-api",
|
||||
"4.21.1",
|
||||
"kQJlZ0gUxdTRRkskT43qiy2kpt9s654LvB0nqoCP6YE=",
|
||||
"4.13.0",
|
||||
"gcmYlY1KDrzbnE9nB8rA44oBZKPSMvv9kNRefoEuud0=",
|
||||
Relocation.of("adventure", "net{}kyori{}adventure")
|
||||
),
|
||||
ADVENTURE_PLATFORM(
|
||||
"me{}lucko",
|
||||
"adventure-platform-api",
|
||||
"4.21.1",
|
||||
"4.13.0",
|
||||
"Kk8IkEMVa9ITBfC3yocpcXQiZ9CwN9VxeWjKUD8I0n0=",
|
||||
Relocation.of("adventure", "net{}kyori{}adventure")
|
||||
),
|
||||
ADVENTURE_PLATFORM_BUKKIT(
|
||||
"me{}lucko",
|
||||
"adventure-platform-bukkit",
|
||||
"4.21.1",
|
||||
"NffwBnfT/Mc6VpsmTcaXPvckv9T4vPJD83adt0C8vao=",
|
||||
"4.13.3",
|
||||
"ZXw7pf+a6tjGdB2WO1rB/KQ+ETLAH8kQFSu3El7jopY=",
|
||||
Relocation.of("adventure", "net{}kyori{}adventure")
|
||||
),
|
||||
ADVENTURE_PLATFORM_BUNGEECORD(
|
||||
"me{}lucko",
|
||||
"adventure-platform-bungeecord",
|
||||
"4.21.1",
|
||||
"4.13.3",
|
||||
"7hnndD6dO6LZoRbtOBdn6OFK0y/T2PqNLHxCg6zaQlo=",
|
||||
Relocation.of("adventure", "net{}kyori{}adventure")
|
||||
),
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ public enum DependencyRepository {
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the {@code dependency} to the {@code file}, ensuring the
|
||||
* Downloads the the {@code dependency} to the {@code file}, ensuring the
|
||||
* downloaded bytes match the checksum.
|
||||
*
|
||||
* @param dependency the dependency to download
|
||||
|
||||
@@ -179,13 +179,6 @@ public interface Message {
|
||||
.color(GRAY)
|
||||
);
|
||||
|
||||
Args0 COMMANDS_DISABLED = () -> prefixed(translatable()
|
||||
// "&3LuckPerms commands are disabled."
|
||||
.key("luckperms.commandsystem.commands-disabled")
|
||||
.color(DARK_AQUA)
|
||||
.append(FULL_STOP)
|
||||
);
|
||||
|
||||
Args2<String, String> FIRST_TIME_SETUP = (label, username) -> joinNewline(
|
||||
// "&3It seems that no permissions have been setup yet!"
|
||||
// "&3Before you can use any of the LuckPerms commands in-game, you need to use the console to give yourself access."
|
||||
|
||||
+2
-3
@@ -54,14 +54,13 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class LuckPermsMessagingService extends AsyncInterface implements InternalMessagingService, IncomingMessageConsumer {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final Set<UUID> receivedMessages;
|
||||
private final ExpiringSet<UUID> receivedMessages;
|
||||
private final PushUpdateBuffer updateBuffer;
|
||||
|
||||
private final MessengerProvider messengerProvider;
|
||||
@@ -75,7 +74,7 @@ public class LuckPermsMessagingService extends AsyncInterface implements Interna
|
||||
this.messenger = messengerProvider.obtain(this);
|
||||
Objects.requireNonNull(this.messenger, "messenger");
|
||||
|
||||
this.receivedMessages = ExpiringSet.newExpiringSet(5, TimeUnit.MINUTES);
|
||||
this.receivedMessages = new ExpiringSet<>(5, TimeUnit.MINUTES);
|
||||
this.updateBuffer = new PushUpdateBuffer(plugin);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,6 @@ public class SqlMessenger extends AbstractSqlMessenger {
|
||||
|
||||
@Override
|
||||
protected String getTableName() {
|
||||
return this.sqlStorage.getStatementProcessor().process("{prefix}messenger");
|
||||
return this.sqlStorage.getStatementProcessor().apply("{prefix}messenger");
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.metastack;
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.metastack;
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.luckperms.api.metastacking.DuplicateRemovalFunction;
|
||||
+4
-10
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.metastack;
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
@@ -220,11 +220,8 @@ public final class StandardStackElements {
|
||||
@Override
|
||||
public boolean shouldAccumulate(@NonNull ChatMetaType type, @NonNull ChatMetaNode<?, ?> node, @Nullable ChatMetaNode<?, ?> current) {
|
||||
Track track = this.plugin.getTrackManager().getIfLoaded(this.trackName);
|
||||
if (track == null) {
|
||||
return false;
|
||||
}
|
||||
PermissionHolder.Identifier origin = node.metadata(InheritanceOriginMetadata.KEY).getOrigin();
|
||||
return origin.getType().equals(PermissionHolder.Identifier.GROUP_TYPE) && track.containsGroup(origin.getName());
|
||||
return track != null && origin.getType().equals(PermissionHolder.Identifier.GROUP_TYPE) && track.containsGroup(origin.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -253,11 +250,8 @@ public final class StandardStackElements {
|
||||
@Override
|
||||
public boolean shouldAccumulate(@NonNull ChatMetaType type, @NonNull ChatMetaNode<?, ?> node, @Nullable ChatMetaNode<?, ?> current) {
|
||||
Track track = this.plugin.getTrackManager().getIfLoaded(this.trackName);
|
||||
if (track == null) {
|
||||
return false;
|
||||
}
|
||||
PermissionHolder.Identifier origin = node.metadata(InheritanceOriginMetadata.KEY).getOrigin();
|
||||
return !(origin.getType().equals(PermissionHolder.Identifier.GROUP_TYPE) && track.containsGroup(origin.getName()));
|
||||
return track != null && !track.containsGroup(origin.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -311,7 +305,7 @@ public final class StandardStackElements {
|
||||
@Override
|
||||
public boolean shouldAccumulate(@NonNull ChatMetaType type, @NonNull ChatMetaNode<?, ?> node, @Nullable ChatMetaNode<?, ?> current) {
|
||||
PermissionHolder.Identifier origin = node.metadata(InheritanceOriginMetadata.KEY).getOrigin();
|
||||
return !(origin.getType().equals(PermissionHolder.Identifier.GROUP_TYPE) && this.groupName.equals(origin.getName()));
|
||||
return !this.groupName.equals(origin.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
+4
-5
@@ -30,7 +30,6 @@ import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.util.ExpiringSet;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -42,16 +41,16 @@ public class UserHousekeeper implements Runnable {
|
||||
private final UserManager<?> userManager;
|
||||
|
||||
// contains the uuids of users who have recently logged in / out
|
||||
private final Set<UUID> recentlyUsed;
|
||||
private final ExpiringSet<UUID> recentlyUsed;
|
||||
|
||||
// contains the uuids of users who have recently been retrieved from the API
|
||||
private final Set<UUID> recentlyUsedApi;
|
||||
private final ExpiringSet<UUID> recentlyUsedApi;
|
||||
|
||||
public UserHousekeeper(LuckPermsPlugin plugin, UserManager<?> userManager, TimeoutSettings timeoutSettings) {
|
||||
this.plugin = plugin;
|
||||
this.userManager = userManager;
|
||||
this.recentlyUsed = ExpiringSet.newExpiringSet(timeoutSettings.duration, timeoutSettings.unit);
|
||||
this.recentlyUsedApi = ExpiringSet.newExpiringSet(5, TimeUnit.MINUTES);
|
||||
this.recentlyUsed = new ExpiringSet<>(timeoutSettings.duration, timeoutSettings.unit);
|
||||
this.recentlyUsedApi = new ExpiringSet<>(5, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
// called when a player attempts a connection or logs out
|
||||
|
||||
+4
-23
@@ -72,7 +72,7 @@ public final class StandardNodeMatchers {
|
||||
return new TypeEquals<>(type);
|
||||
}
|
||||
|
||||
public static class Generic extends ConstraintNodeMatcher<Node> {
|
||||
private static class Generic extends ConstraintNodeMatcher<Node> {
|
||||
Generic(Comparison comparison, String value) {
|
||||
super(comparison, value);
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public final class StandardNodeMatchers {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NodeEquals<T extends Node> extends ConstraintNodeMatcher<T> {
|
||||
private static final class NodeEquals<T extends Node> extends ConstraintNodeMatcher<T> {
|
||||
private final T node;
|
||||
private final NodeEqualityPredicate equalityPredicate;
|
||||
|
||||
@@ -93,14 +93,6 @@ public final class StandardNodeMatchers {
|
||||
this.equalityPredicate = equalityPredicate;
|
||||
}
|
||||
|
||||
public T getNode() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public NodeEqualityPredicate getEqualityPredicate() {
|
||||
return this.equalityPredicate;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public @Nullable T filterConstraintMatch(@NonNull Node node) {
|
||||
@@ -111,16 +103,9 @@ public final class StandardNodeMatchers {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MetaKeyEquals extends ConstraintNodeMatcher<MetaNode> {
|
||||
private final String metaKey;
|
||||
|
||||
private static final class MetaKeyEquals extends ConstraintNodeMatcher<MetaNode> {
|
||||
MetaKeyEquals(String metaKey) {
|
||||
super(Comparison.SIMILAR, Meta.key(metaKey, Comparison.WILDCARD));
|
||||
this.metaKey = metaKey;
|
||||
}
|
||||
|
||||
public String getMetaKey() {
|
||||
return this.metaKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,7 +114,7 @@ public final class StandardNodeMatchers {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TypeEquals<T extends Node> extends ConstraintNodeMatcher<T> {
|
||||
private static final class TypeEquals<T extends Node> extends ConstraintNodeMatcher<T> {
|
||||
private final NodeType<? extends T> type;
|
||||
|
||||
TypeEquals(NodeType<? extends T> type) {
|
||||
@@ -137,10 +122,6 @@ public final class StandardNodeMatchers {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public NodeType<? extends T> getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable T filterConstraintMatch(@NonNull Node node) {
|
||||
return this.type.tryCast(node).orElse(null);
|
||||
|
||||
@@ -210,17 +210,12 @@ public enum ShorthandParser {
|
||||
* Implements an iterator over a given range of ints.
|
||||
*/
|
||||
private abstract static class RangeIterator implements Iterator<String> {
|
||||
private static final int MAX_RANGE = 250;
|
||||
|
||||
private final int max;
|
||||
private int next;
|
||||
|
||||
RangeIterator(int a, int b) {
|
||||
this.max = Math.max(a, b);
|
||||
this.next = Math.min(a, b);
|
||||
if ((this.max - this.next) > MAX_RANGE) {
|
||||
throw new IllegalArgumentException("Range too large");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String toString(int i);
|
||||
|
||||
@@ -33,7 +33,6 @@ import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
|
||||
import me.lucko.luckperms.common.config.generic.adapter.ConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.config.generic.adapter.EnvironmentVariableConfigAdapter;
|
||||
import me.lucko.luckperms.common.config.generic.adapter.FileSecretConfigAdapter;
|
||||
import me.lucko.luckperms.common.config.generic.adapter.MultiConfigurationAdapter;
|
||||
import me.lucko.luckperms.common.config.generic.adapter.SystemPropertyConfigAdapter;
|
||||
import me.lucko.luckperms.common.context.calculator.ConfigurationContextCalculator;
|
||||
@@ -62,7 +61,6 @@ import me.lucko.luckperms.common.storage.misc.DataConstraints;
|
||||
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
import me.lucko.luckperms.common.tasks.SyncTask;
|
||||
import me.lucko.luckperms.common.treeview.AsyncPermissionRegistry;
|
||||
import me.lucko.luckperms.common.treeview.PermissionRegistry;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
import me.lucko.luckperms.common.webeditor.socket.WebEditorSocket;
|
||||
@@ -94,10 +92,10 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
// init during load
|
||||
private DependencyManager dependencyManager;
|
||||
private TranslationManager translationManager;
|
||||
private AsyncPermissionRegistry permissionRegistry;
|
||||
private VerboseHandler verboseHandler;
|
||||
|
||||
// init during enable
|
||||
private VerboseHandler verboseHandler;
|
||||
private PermissionRegistry permissionRegistry;
|
||||
private LogDispatcher logDispatcher;
|
||||
private LuckPermsConfiguration configuration;
|
||||
private OkHttpClient httpClient;
|
||||
@@ -130,8 +128,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
this.translationManager.reload();
|
||||
|
||||
// load some utilities early
|
||||
this.permissionRegistry = new AsyncPermissionRegistry(getBootstrap().getScheduler());
|
||||
this.verboseHandler = new VerboseHandler(getBootstrap().getScheduler());
|
||||
this.permissionRegistry = new PermissionRegistry(getBootstrap().getScheduler());
|
||||
}
|
||||
|
||||
public final void enable() {
|
||||
@@ -141,14 +138,14 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
// send the startup banner
|
||||
Message.STARTUP_BANNER.send(getConsoleSender(), getBootstrap());
|
||||
|
||||
// setup log dispatcher instance early
|
||||
// load some utilities early
|
||||
this.verboseHandler = new VerboseHandler(getBootstrap().getScheduler());
|
||||
this.logDispatcher = new LogDispatcher(this);
|
||||
|
||||
// load configuration
|
||||
getLogger().info("Loading configuration...");
|
||||
ConfigurationAdapter configFileAdapter = provideConfigurationAdapter();
|
||||
this.configuration = new LuckPermsConfiguration(this, new MultiConfigurationAdapter(this,
|
||||
new FileSecretConfigAdapter(this),
|
||||
new SystemPropertyConfigAdapter(this),
|
||||
new EnvironmentVariableConfigAdapter(this),
|
||||
configFileAdapter
|
||||
@@ -208,11 +205,7 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
this.syncTaskBuffer = new SyncTask.Buffer(this);
|
||||
|
||||
// register commands
|
||||
if (skipCommandRegistration()) {
|
||||
getLogger().warn("LuckPerms commands are disabled in the configuration for both console and players. Skipping command registration.");
|
||||
} else {
|
||||
registerCommands();
|
||||
}
|
||||
registerCommands();
|
||||
|
||||
// load internal managers
|
||||
getLogger().info("Loading internal permission managers...");
|
||||
@@ -392,11 +385,6 @@ public abstract class AbstractLuckPermsPlugin implements LuckPermsPlugin {
|
||||
return configFile;
|
||||
}
|
||||
|
||||
protected boolean skipCommandRegistration() {
|
||||
return getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_CONSOLE) &&
|
||||
getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_PLAYERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginLogger getLogger() {
|
||||
return getBootstrap().getPluginLogger();
|
||||
|
||||
@@ -54,7 +54,7 @@ final class FlagUtils {
|
||||
private static byte toByte0(Set<Flag> settings) {
|
||||
byte b = 0;
|
||||
for (Flag setting : settings) {
|
||||
b |= (byte) (1 << setting.ordinal());
|
||||
b |= 1 << setting.ordinal();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class QueryOptionsImpl implements QueryOptions {
|
||||
// computed based on state above
|
||||
private final int hashCode;
|
||||
private Set<Flag> flagsSet = null;
|
||||
private final ContextSatisfyMode overrideContextSatisfyMode;
|
||||
private final ContextSatisfyMode contextSatisfyMode;
|
||||
|
||||
QueryOptionsImpl(QueryMode mode, @Nullable ImmutableContextSet context, byte flags, @Nullable Map<OptionKey<?>, Object> options) {
|
||||
this.mode = mode;
|
||||
@@ -65,7 +65,7 @@ public class QueryOptionsImpl implements QueryOptions {
|
||||
this.options = options == null ? null : ImmutableMap.copyOf(options);
|
||||
|
||||
this.hashCode = calculateHashCode();
|
||||
this.overrideContextSatisfyMode = options == null ? null : (ContextSatisfyMode) options.get(ContextSatisfyMode.KEY);
|
||||
this.contextSatisfyMode = options == null ? null : (ContextSatisfyMode) options.get(ContextSatisfyMode.KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,7 +119,7 @@ public class QueryOptionsImpl implements QueryOptions {
|
||||
public boolean satisfies(@NonNull ContextSet contextSet, @NonNull ContextSatisfyMode defaultContextSatisfyMode) {
|
||||
switch (this.mode) {
|
||||
case CONTEXTUAL:
|
||||
return contextSet.isSatisfiedBy(this.context, this.overrideContextSatisfyMode == null ? defaultContextSatisfyMode : this.overrideContextSatisfyMode);
|
||||
return contextSet.isSatisfiedBy(this.context, this.contextSatisfyMode == null ? defaultContextSatisfyMode : this.contextSatisfyMode);
|
||||
case NON_CONTEXTUAL:
|
||||
return true;
|
||||
default:
|
||||
|
||||
@@ -26,12 +26,8 @@
|
||||
package me.lucko.luckperms.common.sender;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.config.generic.key.ConfigKey;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
@@ -101,19 +97,6 @@ public final class AbstractSender<T> implements Sender {
|
||||
return isConsole() || this.factory.hasPermission(this.sender, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandPermission permission) {
|
||||
boolean readOnlyMode = isConsole()
|
||||
? this.plugin.getConfiguration().get(ConfigKeys.READ_ONLY_MODE_CONSOLE)
|
||||
: this.plugin.getConfiguration().get(ConfigKeys.READ_ONLY_MODE_PLAYERS);
|
||||
|
||||
if (readOnlyMode && !permission.isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasPermission(permission.getPermission());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performCommand(String commandLine) {
|
||||
this.factory.performCommand(this.sender, commandLine);
|
||||
@@ -172,7 +155,7 @@ public final class AbstractSender<T> implements Sender {
|
||||
case 1:
|
||||
return input.get(0);
|
||||
default:
|
||||
return Component.join(JoinConfiguration.separator(Component.empty()), input);
|
||||
return Component.join(Component.empty(), input);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.sender;
|
||||
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
@@ -49,16 +47,6 @@ public abstract class DummyConsoleSender implements Sender {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(CommandPermission permission) {
|
||||
boolean readOnlyMode = this.platform.getConfiguration().get(ConfigKeys.READ_ONLY_MODE_CONSOLE);
|
||||
if (readOnlyMode && !permission.isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performCommand(String commandLine) {
|
||||
|
||||
|
||||
@@ -132,7 +132,9 @@ public interface Sender {
|
||||
* @param permission the permission to check for
|
||||
* @return true if the sender has the permission
|
||||
*/
|
||||
boolean hasPermission(CommandPermission permission);
|
||||
default boolean hasPermission(CommandPermission permission) {
|
||||
return hasPermission(permission.getPermission());
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the sender perform a command.
|
||||
|
||||
@@ -37,7 +37,6 @@ import me.lucko.luckperms.common.storage.implementation.file.loader.JsonLoader;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.loader.TomlLoader;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.loader.YamlLoader;
|
||||
import me.lucko.luckperms.common.storage.implementation.mongodb.MongoStorage;
|
||||
import me.lucko.luckperms.common.storage.implementation.rest.RestStorage;
|
||||
import me.lucko.luckperms.common.storage.implementation.split.SplitStorage;
|
||||
import me.lucko.luckperms.common.storage.implementation.split.SplitStorageType;
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.SqlStorage;
|
||||
@@ -130,12 +129,6 @@ public class StorageFactory {
|
||||
this.plugin.getConfiguration().get(ConfigKeys.MONGODB_COLLECTION_PREFIX),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.MONGODB_CONNECTION_URI)
|
||||
);
|
||||
case REST:
|
||||
return new RestStorage(
|
||||
this.plugin,
|
||||
this.plugin.getConfiguration().get(ConfigKeys.REST_STORAGE_URL),
|
||||
this.plugin.getConfiguration().get(ConfigKeys.REST_STORAGE_AUTH_KEY)
|
||||
);
|
||||
case YAML:
|
||||
return new SeparatedConfigurateStorage(this.plugin, "YAML", new YamlLoader(), ".yml", "yaml-storage");
|
||||
case JSON:
|
||||
|
||||
@@ -51,9 +51,6 @@ public enum StorageType {
|
||||
SQLITE("SQLite", "sqlite"),
|
||||
H2("H2", "h2"),
|
||||
|
||||
// REST
|
||||
REST("REST", "rest"),
|
||||
|
||||
// Custom
|
||||
CUSTOM("Custom", "custom");
|
||||
|
||||
|
||||
+1
-2
@@ -36,7 +36,6 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
@@ -98,7 +97,7 @@ public class FileWatcher extends AbstractFileWatcher {
|
||||
private final Path path;
|
||||
|
||||
/** A set of files which have been modified recently */
|
||||
private final Set<String> recentlyModifiedFiles = ExpiringSet.newExpiringSet(4, TimeUnit.SECONDS);
|
||||
private final ExpiringSet<String> recentlyModifiedFiles = new ExpiringSet<>(4, TimeUnit.SECONDS);
|
||||
|
||||
/** The listener callback functions */
|
||||
private final List<Consumer<Path>> callbacks = new CopyOnWriteArrayList<>();
|
||||
|
||||
+3
-6
@@ -25,7 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.implementation.mongodb;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientOptions;
|
||||
@@ -587,8 +586,7 @@ public class MongoStorage implements StorageImplementation {
|
||||
return new Document("_id", track.getName()).append("groups", track.getGroups());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static Document nodeToDoc(Node node) {
|
||||
private static Document nodeToDoc(Node node) {
|
||||
Document document = new Document()
|
||||
.append("key", node.getKey())
|
||||
.append("value", node.getValue());
|
||||
@@ -605,8 +603,7 @@ public class MongoStorage implements StorageImplementation {
|
||||
return document;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static Node nodeFromDoc(Document document) {
|
||||
private static Node nodeFromDoc(Document document) {
|
||||
String key = document.containsKey("permission") ? document.getString("permission") : document.getString("key");
|
||||
|
||||
if (key == null || key.isEmpty()) {
|
||||
@@ -625,7 +622,7 @@ public class MongoStorage implements StorageImplementation {
|
||||
}
|
||||
|
||||
if (document.containsKey("expiry")) {
|
||||
builder.expiry(((Number) document.get("expiry")).longValue());
|
||||
builder.expiry((long) document.get("expiry"));
|
||||
}
|
||||
|
||||
if (document.containsKey("context") && document.get("context") instanceof List) {
|
||||
|
||||
-664
@@ -1,664 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.storage.implementation.rest;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.actionlog.filter.ActionFields;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.filter.Comparison;
|
||||
import me.lucko.luckperms.common.filter.Constraint;
|
||||
import me.lucko.luckperms.common.filter.Filter;
|
||||
import me.lucko.luckperms.common.filter.FilterField;
|
||||
import me.lucko.luckperms.common.filter.FilterList;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.factory.NodeBuilders;
|
||||
import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher;
|
||||
import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.StorageMetadata;
|
||||
import me.lucko.luckperms.common.storage.implementation.StorageImplementation;
|
||||
import me.lucko.luckperms.common.storage.misc.NodeEntry;
|
||||
import me.lucko.luckperms.common.storage.misc.PlayerSaveResultImpl;
|
||||
import me.lucko.luckperms.common.util.Difference;
|
||||
import me.lucko.luckperms.common.util.Iterators;
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
import net.luckperms.api.context.ContextSet;
|
||||
import net.luckperms.api.model.PlayerSaveResult;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeBuilder;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.rest.LuckPermsRestClient;
|
||||
import net.luckperms.rest.model.ActionPage;
|
||||
import net.luckperms.rest.model.Context;
|
||||
import net.luckperms.rest.model.CreateGroupRequest;
|
||||
import net.luckperms.rest.model.CreateTrackRequest;
|
||||
import net.luckperms.rest.model.CreateUserRequest;
|
||||
import net.luckperms.rest.model.GroupSearchResult;
|
||||
import net.luckperms.rest.model.Health;
|
||||
import net.luckperms.rest.model.UpdateTrackRequest;
|
||||
import net.luckperms.rest.model.UpdateUserRequest;
|
||||
import net.luckperms.rest.model.UserLookupResult;
|
||||
import net.luckperms.rest.model.UserSearchResult;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import retrofit2.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class RestStorage implements StorageImplementation {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final LuckPermsRestClient client;
|
||||
|
||||
public RestStorage(LuckPermsPlugin plugin, String baseUrl, String apiKey) {
|
||||
this.plugin = plugin;
|
||||
this.client = LuckPermsRestClient.builder()
|
||||
.baseUrl(baseUrl)
|
||||
.apiKey(apiKey)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuckPermsPlugin getPlugin() {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImplementationName() {
|
||||
return "REST";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
Health health = this.client.misc().health().execute().body();
|
||||
if (health == null || !health.healthy()) {
|
||||
this.plugin.getLogger().warn("REST storage endpoint is unhealthy");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
this.client.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageMetadata getMeta() {
|
||||
StorageMetadata metadata = new StorageMetadata();
|
||||
|
||||
boolean success = true;
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
Health health = this.client.misc().health().execute().body();
|
||||
if (health == null || !health.healthy()) {
|
||||
success = false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
int duration = (int) (System.currentTimeMillis() - start);
|
||||
metadata.ping(duration);
|
||||
}
|
||||
|
||||
metadata.connected(success);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logAction(Action entry) throws IOException {
|
||||
this.client.actions().submit(convertAction(entry)).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LogPage getLogPage(FilterList<Action> filters, @Nullable PageParameters page) throws Exception {
|
||||
Response<ActionPage> resp = null;
|
||||
|
||||
if (filters.isEmpty()) {
|
||||
// ActionFilters.all()
|
||||
resp = page != null
|
||||
? this.client.actions().query(page.pageSize(), page.pageNumber()).execute()
|
||||
: this.client.actions().query().execute();
|
||||
|
||||
} else if (filters.size() == 1) {
|
||||
// ActionFilters.source(uniqueId)
|
||||
Filter<Action, ?> filter = filters.get(0);
|
||||
if (filter.field() == ActionFields.SOURCE_UNIQUE_ID && filter.constraint().comparison() == Comparison.EQUAL) {
|
||||
UUID uniqueId = (UUID) filter.constraint().value();
|
||||
resp = page != null
|
||||
? this.client.actions().querySource(uniqueId, page.pageSize(), page.pageNumber()).execute()
|
||||
: this.client.actions().querySource(uniqueId).execute();
|
||||
}
|
||||
|
||||
} else if (filters.operator() == FilterList.LogicalOperator.AND && filters.size() == 2) {
|
||||
Filter<Action, ?> filterA = filters.get(0);
|
||||
Filter<Action, ?> filterB = filters.get(1);
|
||||
|
||||
if (filterA.field() == ActionFields.TARGET_TYPE && filterA.constraint().comparison() == Comparison.EQUAL) {
|
||||
Action.Target.Type type = (Action.Target.Type) filterA.constraint().value();
|
||||
|
||||
if (type == Action.Target.Type.USER) {
|
||||
// ActionFilters.user(uniqueId)
|
||||
if (filterB.field() == ActionFields.TARGET_UNIQUE_ID && filterB.constraint().comparison() == Comparison.EQUAL) {
|
||||
UUID uniqueId = (UUID) filterB.constraint().value();
|
||||
resp = page != null
|
||||
? this.client.actions().queryTargetUser(uniqueId, page.pageSize(), page.pageNumber()).execute()
|
||||
: this.client.actions().queryTargetUser(uniqueId).execute();
|
||||
}
|
||||
} else if (type == Action.Target.Type.GROUP) {
|
||||
// ActionFilters.group(name)
|
||||
if (filterB.field() == ActionFields.TARGET_NAME && filterB.constraint().comparison() == Comparison.EQUAL) {
|
||||
String name = (String) filterB.constraint().value();
|
||||
resp = page != null
|
||||
? this.client.actions().queryTargetGroup(name, page.pageSize(), page.pageNumber()).execute()
|
||||
: this.client.actions().queryTargetGroup(name).execute();
|
||||
}
|
||||
} else if (type == Action.Target.Type.TRACK) {
|
||||
// ActionFilters.track(name)
|
||||
if (filterB.field() == ActionFields.TARGET_NAME && filterB.constraint().comparison() == Comparison.EQUAL) {
|
||||
String name = (String) filterB.constraint().value();
|
||||
resp = page != null
|
||||
? this.client.actions().queryTargetTrack(name, page.pageSize(), page.pageNumber()).execute()
|
||||
: this.client.actions().queryTargetTrack(name).execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (filters.operator() == FilterList.LogicalOperator.OR && filters.size() == 3) {
|
||||
// ActionFilters.search(query)
|
||||
ImmutableList<FilterField<Action, String>> searchFields = ImmutableList.of(ActionFields.SOURCE_NAME, ActionFields.TARGET_NAME, ActionFields.DESCRIPTION);
|
||||
if (filters.stream().allMatch(filter -> filter.constraint().comparison() == Comparison.SIMILAR && searchFields.contains(filter.field()))) {
|
||||
String query = (String) filters.get(0).constraint().value();
|
||||
if (!query.startsWith("%") || !query.endsWith("%")) {
|
||||
throw new IllegalArgumentException("Unsupported search query: " + query);
|
||||
}
|
||||
String searchTerm = query.substring(1, query.length() - 1);
|
||||
|
||||
resp = page != null
|
||||
? this.client.actions().querySearch(searchTerm, page.pageSize(), page.pageNumber()).execute()
|
||||
: this.client.actions().querySearch(searchTerm).execute();
|
||||
}
|
||||
}
|
||||
|
||||
if (resp == null) {
|
||||
throw new UnsupportedOperationException("Unsupported filter: " + filters);
|
||||
}
|
||||
|
||||
ActionPage body = Objects.requireNonNull(resp.body(), "resp.body()");
|
||||
return LogPage.of(
|
||||
body.entries().stream().map(RestStorage::convertAction).collect(Collectors.toList()),
|
||||
page,
|
||||
body.overallSize()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyBulkUpdate(BulkUpdate bulkUpdate) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public User loadUser(UUID uniqueId, String username) throws Exception {
|
||||
net.luckperms.rest.model.User remoteUser = this.client.users().get(uniqueId).execute().body();
|
||||
if (remoteUser == null) {
|
||||
throw new IllegalStateException("Client did not return a user for " + uniqueId);
|
||||
}
|
||||
|
||||
User user = this.plugin.getUserManager().getOrMake(uniqueId, username);
|
||||
user.setUsername(remoteUser.username(), true);
|
||||
user.loadNodesFromStorage(remoteUser.nodes().stream().map(RestStorage::convertNode).collect(Collectors.toList()));
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, User> loadUsers(Set<UUID> uniqueIds) throws Exception {
|
||||
return uniqueIds.parallelStream()
|
||||
.map(uniqueId -> {
|
||||
try {
|
||||
return loadUser(uniqueId, null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toMap(User::getUniqueId, Function.identity()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveUser(User user) throws Exception {
|
||||
Difference<Node> changes = user.normalData().exportChanges(results -> {
|
||||
if (this.plugin.getUserManager().isNonDefaultUser(user)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the only change is adding the default node, we don't need to export
|
||||
if (results.getChanges().size() == 1) {
|
||||
Difference.Change<Node> onlyChange = results.getChanges().iterator().next();
|
||||
return !(onlyChange.type() == Difference.ChangeType.ADD && this.plugin.getUserManager().isDefaultNode(onlyChange.value()));
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
if (changes == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String username = user.getUsername().orElse(null);
|
||||
if (username != null) {
|
||||
this.client.users().update(user.getUniqueId(), new UpdateUserRequest(username)).execute();
|
||||
}
|
||||
|
||||
Set<Node> added = changes.getAdded();
|
||||
Set<Node> removed = changes.getRemoved();
|
||||
|
||||
if (!removed.isEmpty()) {
|
||||
this.client.users().nodesDelete(user.getUniqueId(), removed.stream().map(RestStorage::convertNode).collect(Collectors.toList())).execute();
|
||||
}
|
||||
if (!added.isEmpty()) {
|
||||
this.client.users().nodesAdd(user.getUniqueId(), added.stream().map(RestStorage::convertNode).collect(Collectors.toList())).execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> getUniqueUsers() throws Exception {
|
||||
return this.client.users().list().execute().body();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Node> List<NodeEntry<UUID, N>> searchUserNodes(ConstraintNodeMatcher<N> matcher) throws Exception {
|
||||
List<UserSearchResult> results;
|
||||
if (matcher instanceof StandardNodeMatchers.TypeEquals) {
|
||||
NodeType<? extends N> type = ((StandardNodeMatchers.TypeEquals<N>) matcher).getType();
|
||||
results = this.client.users().searchNodesByType(convertNodeType(type)).execute().body();
|
||||
} else {
|
||||
Constraint<String> constraint = matcher.getConstraint();
|
||||
Comparison comparison = constraint.comparison();
|
||||
String value = constraint.value();
|
||||
|
||||
if (comparison == Comparison.EQUAL) {
|
||||
results = this.client.users().searchNodesByKey(value).execute().body();
|
||||
} else if (comparison == Comparison.SIMILAR) {
|
||||
long wildcards = value.chars().filter(ch -> ch == '%').count();
|
||||
if (wildcards == 0) {
|
||||
results = this.client.users().searchNodesByKey(value).execute().body();
|
||||
} else if (wildcards == 1 && value.endsWith("%")) {
|
||||
results = this.client.users().searchNodesByKeyStartsWith(value.substring(0, value.length() - 1)).execute().body();
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported constraint: " + constraint);
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported constraint: " + constraint);
|
||||
}
|
||||
}
|
||||
|
||||
if (results == null) {
|
||||
throw new IllegalStateException("Client returned null results");
|
||||
}
|
||||
|
||||
List<NodeEntry<UUID, N>> held = new ArrayList<>();
|
||||
for (UserSearchResult result : results) {
|
||||
UUID uniqueId = result.uniqueId();
|
||||
for (net.luckperms.rest.model.Node node : result.results()) {
|
||||
N match = matcher.filterConstraintMatch(convertNode(node));
|
||||
if (match != null) {
|
||||
held.add(NodeEntry.of(uniqueId, match));
|
||||
}
|
||||
}
|
||||
}
|
||||
return held;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Group createAndLoadGroup(String name) throws Exception {
|
||||
net.luckperms.rest.model.Group remoteGroup = this.client.groups().create(new CreateGroupRequest(name)).execute().body();
|
||||
if (remoteGroup == null) {
|
||||
remoteGroup = this.client.groups().get(name).execute().body();
|
||||
if (remoteGroup == null) {
|
||||
throw new IllegalStateException("Unable to create group: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
Group group = this.plugin.getGroupManager().getOrMake(name);
|
||||
group.loadNodesFromStorage(remoteGroup.nodes().stream().map(RestStorage::convertNode).collect(Collectors.toList()));
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Group> loadGroup(String name) throws Exception {
|
||||
net.luckperms.rest.model.Group remoteGroup = this.client.groups().get(name).execute().body();
|
||||
if (remoteGroup == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Group group = this.plugin.getGroupManager().getOrMake(name);
|
||||
group.loadNodesFromStorage(remoteGroup.nodes().stream().map(RestStorage::convertNode).collect(Collectors.toList()));
|
||||
return Optional.of(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAllGroups() throws Exception {
|
||||
Set<String> groups = this.client.groups().list().execute().body();
|
||||
if (groups == null) {
|
||||
throw new IllegalStateException("Client returned a null list of groups");
|
||||
}
|
||||
|
||||
if (!Iterators.tryIterate(groups, this::loadGroup)) {
|
||||
throw new RuntimeException("Exception occurred whilst loading a group");
|
||||
}
|
||||
|
||||
this.plugin.getGroupManager().retainAll(groups);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveGroup(Group group) throws Exception {
|
||||
Difference<Node> changes = group.normalData().exportChanges(c -> true);
|
||||
|
||||
Set<Node> added = changes.getAdded();
|
||||
Set<Node> removed = changes.getRemoved();
|
||||
|
||||
if (!removed.isEmpty()) {
|
||||
this.client.groups().nodesDelete(group.getName(), removed.stream().map(RestStorage::convertNode).collect(Collectors.toList())).execute();
|
||||
}
|
||||
if (!added.isEmpty()) {
|
||||
this.client.groups().nodesAdd(group.getName(), added.stream().map(RestStorage::convertNode).collect(Collectors.toList())).execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteGroup(Group group) throws Exception {
|
||||
this.client.groups().delete(group.getName()).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends Node> List<NodeEntry<String, N>> searchGroupNodes(ConstraintNodeMatcher<N> matcher) throws Exception {
|
||||
List<GroupSearchResult> results;
|
||||
if (matcher instanceof StandardNodeMatchers.TypeEquals) {
|
||||
NodeType<? extends N> type = ((StandardNodeMatchers.TypeEquals<N>) matcher).getType();
|
||||
results = this.client.groups().searchNodesByType(convertNodeType(type)).execute().body();
|
||||
} else {
|
||||
Constraint<String> constraint = matcher.getConstraint();
|
||||
Comparison comparison = constraint.comparison();
|
||||
String value = constraint.value();
|
||||
|
||||
if (comparison == Comparison.EQUAL) {
|
||||
results = this.client.groups().searchNodesByKey(value).execute().body();
|
||||
} else if (comparison == Comparison.SIMILAR) {
|
||||
long wildcards = value.chars().filter(ch -> ch == '%').count();
|
||||
if (wildcards == 0) {
|
||||
results = this.client.groups().searchNodesByKey(value).execute().body();
|
||||
} else if (wildcards == 1 && value.endsWith("%")) {
|
||||
results = this.client.groups().searchNodesByKeyStartsWith(value.substring(0, value.length() - 1)).execute().body();
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported constraint: " + constraint);
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported constraint: " + constraint);
|
||||
}
|
||||
}
|
||||
|
||||
if (results == null) {
|
||||
throw new IllegalStateException("Client returned null results");
|
||||
}
|
||||
|
||||
List<NodeEntry<String, N>> held = new ArrayList<>();
|
||||
for (GroupSearchResult result : results) {
|
||||
String name = result.name();
|
||||
for (net.luckperms.rest.model.Node node : result.results()) {
|
||||
N match = matcher.filterConstraintMatch(convertNode(node));
|
||||
if (match != null) {
|
||||
held.add(NodeEntry.of(name, match));
|
||||
}
|
||||
}
|
||||
}
|
||||
return held;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Track createAndLoadTrack(String name) throws Exception {
|
||||
net.luckperms.rest.model.Track remoteTrack = this.client.tracks().create(new CreateTrackRequest(name)).execute().body();
|
||||
if (remoteTrack == null) {
|
||||
remoteTrack = this.client.tracks().get(name).execute().body();
|
||||
if (remoteTrack == null) {
|
||||
throw new IllegalStateException("Unable to create track: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
Track track = this.plugin.getTrackManager().getOrMake(name);
|
||||
track.setGroups(remoteTrack.groups());
|
||||
return track;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Track> loadTrack(String name) throws Exception {
|
||||
net.luckperms.rest.model.Track remoteTrack = this.client.tracks().get(name).execute().body();
|
||||
if (remoteTrack == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
Track track = this.plugin.getTrackManager().getOrMake(name);
|
||||
track.setGroups(remoteTrack.groups());
|
||||
return Optional.of(track);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAllTracks() throws Exception {
|
||||
Set<String> tracks = this.client.tracks().list().execute().body();
|
||||
if (tracks == null) {
|
||||
throw new IllegalStateException("Client returned a null list of tracks");
|
||||
}
|
||||
|
||||
if (!Iterators.tryIterate(tracks, this::loadTrack)) {
|
||||
throw new RuntimeException("Exception occurred whilst loading a track");
|
||||
}
|
||||
|
||||
this.plugin.getTrackManager().retainAll(tracks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveTrack(Track track) throws Exception {
|
||||
this.client.tracks().update(track.getName(), new UpdateTrackRequest(track.getGroups())).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTrack(Track track) throws Exception {
|
||||
this.client.tracks().delete(track.getName()).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerSaveResult savePlayerData(UUID uniqueId, String username) throws Exception {
|
||||
net.luckperms.rest.model.PlayerSaveResult remoteResult = this.client.users().create(new CreateUserRequest(uniqueId, username)).execute().body();
|
||||
|
||||
Set<PlayerSaveResult.Outcome> outcomes = remoteResult.outcomes().stream().map(outcome -> {
|
||||
switch (outcome) {
|
||||
case CLEAN_INSERT:
|
||||
return PlayerSaveResult.Outcome.CLEAN_INSERT;
|
||||
case NO_CHANGE:
|
||||
return PlayerSaveResult.Outcome.NO_CHANGE;
|
||||
case USERNAME_UPDATED:
|
||||
return PlayerSaveResult.Outcome.USERNAME_UPDATED;
|
||||
case OTHER_UNIQUE_IDS_PRESENT_FOR_USERNAME:
|
||||
return PlayerSaveResult.Outcome.OTHER_UNIQUE_IDS_PRESENT_FOR_USERNAME;
|
||||
default:
|
||||
throw new AssertionError(outcome);
|
||||
}
|
||||
}).collect(Collectors.toSet());
|
||||
|
||||
if (outcomes.isEmpty()) {
|
||||
throw new IllegalStateException("No outcomes returned");
|
||||
}
|
||||
|
||||
PlayerSaveResultImpl result;
|
||||
if (outcomes.contains(PlayerSaveResult.Outcome.CLEAN_INSERT)) {
|
||||
result = PlayerSaveResultImpl.cleanInsert();
|
||||
} else if (outcomes.contains(PlayerSaveResult.Outcome.NO_CHANGE)) {
|
||||
result = PlayerSaveResultImpl.noChange();
|
||||
} else if (outcomes.contains(PlayerSaveResult.Outcome.USERNAME_UPDATED)) {
|
||||
result = PlayerSaveResultImpl.usernameUpdated(remoteResult.previousUsername());
|
||||
} else {
|
||||
throw new IllegalStateException("No base outcome returned");
|
||||
}
|
||||
|
||||
if (outcomes.contains(PlayerSaveResult.Outcome.OTHER_UNIQUE_IDS_PRESENT_FOR_USERNAME)) {
|
||||
result = result.withOtherUuidsPresent(remoteResult.otherUniqueIds());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePlayerData(UUID uniqueId) throws Exception {
|
||||
this.client.users().delete(uniqueId, true).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable UUID getPlayerUniqueId(String username) throws Exception {
|
||||
UserLookupResult result = this.client.users().lookup(username).execute().body();
|
||||
return result == null ? null : result.uniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getPlayerName(UUID uniqueId) throws Exception {
|
||||
UserLookupResult result = this.client.users().lookup(uniqueId).execute().body();
|
||||
return result == null ? null : result.username();
|
||||
}
|
||||
|
||||
private static net.luckperms.rest.model.Action convertAction(Action action) {
|
||||
return new net.luckperms.rest.model.Action(
|
||||
action.getTimestamp().getEpochSecond(),
|
||||
new net.luckperms.rest.model.Action.Source(
|
||||
action.getSource().getUniqueId(),
|
||||
action.getSource().getName()
|
||||
),
|
||||
new net.luckperms.rest.model.Action.Target(
|
||||
action.getTarget().getUniqueId().orElse(null),
|
||||
action.getTarget().getName(),
|
||||
convertActionTargetType(action.getTarget().getType())
|
||||
),
|
||||
action.getDescription()
|
||||
);
|
||||
}
|
||||
|
||||
private static net.luckperms.rest.model.Action.Target.Type convertActionTargetType(Action.Target.Type type) {
|
||||
switch (type) {
|
||||
case USER:
|
||||
return net.luckperms.rest.model.Action.Target.Type.USER;
|
||||
case GROUP:
|
||||
return net.luckperms.rest.model.Action.Target.Type.GROUP;
|
||||
case TRACK:
|
||||
return net.luckperms.rest.model.Action.Target.Type.TRACK;
|
||||
default:
|
||||
throw new AssertionError(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static LoggedAction convertAction(net.luckperms.rest.model.Action action) {
|
||||
return LoggedAction.build()
|
||||
.timestamp(Instant.ofEpochSecond(action.timestamp()))
|
||||
.source(action.source().uniqueId())
|
||||
.sourceName(action.source().name())
|
||||
.target(action.target().uniqueId())
|
||||
.targetName(action.target().name())
|
||||
.targetType(convertActionTargetType(action.target().type()))
|
||||
.description(action.description())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static Action.Target.Type convertActionTargetType(net.luckperms.rest.model.Action.Target.Type type) {
|
||||
switch (type) {
|
||||
case USER:
|
||||
return Action.Target.Type.USER;
|
||||
case GROUP:
|
||||
return Action.Target.Type.GROUP;
|
||||
case TRACK:
|
||||
return Action.Target.Type.TRACK;
|
||||
default:
|
||||
throw new AssertionError(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static Node convertNode(net.luckperms.rest.model.Node node) {
|
||||
NodeBuilder<?, ?> builder = NodeBuilders.determineMostApplicable(node.key());
|
||||
if (node.value() != null) {
|
||||
builder.value(node.value());
|
||||
}
|
||||
if (node.context() != null) {
|
||||
builder.context(convertContexts(node.context()));
|
||||
}
|
||||
if (node.expiry() != null) {
|
||||
builder.expiry(node.expiry());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static net.luckperms.rest.model.Node convertNode(Node node) {
|
||||
return new net.luckperms.rest.model.Node(
|
||||
node.getKey(),
|
||||
node.getValue(),
|
||||
convertContexts(node.getContexts()),
|
||||
node.getExpiry() == null ? null : node.getExpiry().getEpochSecond()
|
||||
);
|
||||
}
|
||||
|
||||
public static ContextSet convertContexts(Set<Context> contexts) {
|
||||
ImmutableContextSetImpl.BuilderImpl builder = new ImmutableContextSetImpl.BuilderImpl();
|
||||
for (Context context : contexts) {
|
||||
builder.add(context.key(), context.value());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static Set<Context> convertContexts(ContextSet contexts) {
|
||||
return StreamSupport.stream(contexts.spliterator(), false)
|
||||
.map(c -> new Context(c.getKey(), c.getValue()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static net.luckperms.rest.model.NodeType convertNodeType(NodeType<?> type) {
|
||||
if (type == NodeType.REGEX_PERMISSION) return net.luckperms.rest.model.NodeType.REGEX_PERMISSION;
|
||||
if (type == NodeType.INHERITANCE) return net.luckperms.rest.model.NodeType.INHERITANCE;
|
||||
if (type == NodeType.PREFIX) return net.luckperms.rest.model.NodeType.PREFIX;
|
||||
if (type == NodeType.SUFFIX) return net.luckperms.rest.model.NodeType.SUFFIX;
|
||||
if (type == NodeType.META) return net.luckperms.rest.model.NodeType.META;
|
||||
if (type == NodeType.WEIGHT) return net.luckperms.rest.model.NodeType.WEIGHT;
|
||||
if (type == NodeType.DISPLAY_NAME) return net.luckperms.rest.model.NodeType.DISPLAY_NAME;
|
||||
throw new IllegalArgumentException("Invalid type: " + type.name());
|
||||
}
|
||||
}
|
||||
+1
-40
@@ -32,24 +32,10 @@ import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class SchemaReader {
|
||||
private SchemaReader() {}
|
||||
|
||||
private static final Pattern CREATE_TABLE_PATTERN = Pattern.compile("^CREATE TABLE [`\"']([^`\"']+)[`\"'].*");
|
||||
private static final Pattern CREATE_INDEX_PATTERN = Pattern.compile("^CREATE INDEX.* ON [`\"']([^`\"']+)[`\"'].*");
|
||||
|
||||
/**
|
||||
* Parses a schema file to a list of SQL statements
|
||||
*
|
||||
* @param is the input stream to read from
|
||||
* @return a list of statements
|
||||
* @throws IOException if an error occurs whilst reading the file
|
||||
*/
|
||||
public static List<String> getStatements(InputStream is) throws IOException {
|
||||
List<String> queries = new LinkedList<>();
|
||||
|
||||
@@ -67,7 +53,7 @@ public final class SchemaReader {
|
||||
if (line.endsWith(";")) {
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
|
||||
String result = sb.toString().trim().replaceAll(" +", " ");
|
||||
String result = sb.toString().trim();
|
||||
if (!result.isEmpty()) {
|
||||
queries.add(result);
|
||||
}
|
||||
@@ -80,29 +66,4 @@ public final class SchemaReader {
|
||||
|
||||
return queries;
|
||||
}
|
||||
|
||||
public static String tableFromStatement(String statement) {
|
||||
Matcher table = CREATE_TABLE_PATTERN.matcher(statement);
|
||||
if (table.matches()) {
|
||||
return table.group(1).toLowerCase(Locale.ROOT);
|
||||
}
|
||||
Matcher index = CREATE_INDEX_PATTERN.matcher(statement);
|
||||
if (index.matches()) {
|
||||
return index.group(1).toLowerCase(Locale.ROOT);
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown statement type: " + statement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters which statements should be executed based on the current list of tables in the database
|
||||
*
|
||||
* @param statements the statements to filter
|
||||
* @param currentTables the current tables in the database
|
||||
* @return the filtered list of statements
|
||||
*/
|
||||
public static List<String> filterStatements(List<String> statements, List<String> currentTables) {
|
||||
return statements.stream()
|
||||
.filter(statement -> !currentTables.contains(tableFromStatement(statement)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+51
-51
@@ -80,6 +80,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SqlStorage implements StorageImplementation {
|
||||
@@ -136,7 +137,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
private final ConnectionFactory connectionFactory;
|
||||
private final StatementProcessor statementProcessor;
|
||||
private final Function<String, String> statementProcessor;
|
||||
|
||||
public SqlStorage(LuckPermsPlugin plugin, ConnectionFactory connectionFactory, String tablePrefix) {
|
||||
this.plugin = plugin;
|
||||
@@ -158,7 +159,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
return this.connectionFactory;
|
||||
}
|
||||
|
||||
public StatementProcessor getStatementProcessor() {
|
||||
public Function<String, String> getStatementProcessor() {
|
||||
return this.statementProcessor;
|
||||
}
|
||||
|
||||
@@ -166,32 +167,30 @@ public class SqlStorage implements StorageImplementation {
|
||||
public void init() throws Exception {
|
||||
this.connectionFactory.init(this.plugin);
|
||||
|
||||
List<String> tables;
|
||||
boolean tableExists;
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
tables = listTables(c);
|
||||
tableExists = tableExists(c, this.statementProcessor.apply("{prefix}user_permissions"));
|
||||
}
|
||||
|
||||
if (!tableExists) {
|
||||
applySchema();
|
||||
}
|
||||
applySchema(tables);
|
||||
}
|
||||
|
||||
private void applySchema(List<String> existingTables) throws IOException, SQLException {
|
||||
String schemaFileName = "me/lucko/luckperms/schema/" + this.connectionFactory.getImplementationName().toLowerCase(Locale.ROOT) + ".sql";
|
||||
|
||||
private void applySchema() throws IOException, SQLException {
|
||||
List<String> statements;
|
||||
|
||||
String schemaFileName = "me/lucko/luckperms/schema/" + this.connectionFactory.getImplementationName().toLowerCase(Locale.ROOT) + ".sql";
|
||||
try (InputStream is = this.plugin.getBootstrap().getResourceStream(schemaFileName)) {
|
||||
if (is == null) {
|
||||
throw new IOException("Couldn't locate schema file for " + this.connectionFactory.getImplementationName());
|
||||
}
|
||||
|
||||
statements = SchemaReader.getStatements(is).stream()
|
||||
.map(this.statementProcessor::process)
|
||||
.map(this.statementProcessor)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
statements = SchemaReader.filterStatements(statements, existingTables);
|
||||
if (statements.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (Connection connection = this.connectionFactory.getConnection()) {
|
||||
boolean utf8mb4Unsupported = false;
|
||||
|
||||
@@ -241,7 +240,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
@Override
|
||||
public void logAction(Action entry) throws SQLException {
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(ACTION_INSERT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(ACTION_INSERT))) {
|
||||
writeAction(entry, ps);
|
||||
ps.execute();
|
||||
}
|
||||
@@ -289,7 +288,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
if (bulkUpdate.getDataType().isIncludingUsers()) {
|
||||
StatementProcessor tableReplacement = s -> s.replace("{table}", "{prefix}user_permissions");
|
||||
Function<String, String> tableReplacement = s -> s.replace("{table}", "{prefix}user_permissions");
|
||||
|
||||
BulkUpdateSqlBuilder sqlBuilder = new BulkUpdateSqlBuilder();
|
||||
sqlBuilder.visit(bulkUpdate);
|
||||
@@ -320,7 +319,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
}
|
||||
|
||||
if (bulkUpdate.getDataType().isIncludingGroups()) {
|
||||
StatementProcessor tableReplacement = s -> s.replace("{table}", "{prefix}group_permissions");
|
||||
Function<String, String> tableReplacement = s -> s.replace("{table}", "{prefix}group_permissions");
|
||||
|
||||
BulkUpdateSqlBuilder sqlBuilder = new BulkUpdateSqlBuilder();
|
||||
sqlBuilder.visit(bulkUpdate);
|
||||
@@ -449,7 +448,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
public Set<UUID> getUniqueUsers() throws SQLException {
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(USER_PERMISSIONS_SELECT_DISTINCT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(USER_PERMISSIONS_SELECT_DISTINCT))) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
UUID uuid = Uuids.fromString(rs.getString("uuid"));
|
||||
@@ -497,7 +496,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
public Group createAndLoadGroup(String name) throws SQLException {
|
||||
String query = GROUP_INSERT.getOrDefault(this.connectionFactory.getImplementationName(), GROUP_INSERT_DEFAULT);
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(query))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(query))) {
|
||||
ps.setString(1, name);
|
||||
ps.execute();
|
||||
}
|
||||
@@ -560,7 +559,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
deleteGroupPermissions(c, group.getName());
|
||||
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(GROUP_DELETE))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(GROUP_DELETE))) {
|
||||
ps.setString(1, group.getName());
|
||||
ps.execute();
|
||||
}
|
||||
@@ -663,7 +662,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
@Override
|
||||
public void deleteTrack(Track track) throws SQLException {
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(TRACK_DELETE))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(TRACK_DELETE))) {
|
||||
ps.setString(1, track.getName());
|
||||
ps.execute();
|
||||
}
|
||||
@@ -680,7 +679,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
SqlPlayerData existingPlayerData = selectPlayerData(c, uniqueId);
|
||||
if (existingPlayerData == null) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_INSERT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_INSERT))) {
|
||||
ps.setString(1, uniqueId.toString());
|
||||
ps.setString(2, username);
|
||||
ps.setString(3, GroupManager.DEFAULT_GROUP_NAME);
|
||||
@@ -689,7 +688,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
} else {
|
||||
oldUsername = existingPlayerData.username;
|
||||
if (!username.equals(oldUsername)) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_UPDATE_USERNAME_FOR_UUID))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_UPDATE_USERNAME_FOR_UUID))) {
|
||||
ps.setString(1, username);
|
||||
ps.setString(2, uniqueId.toString());
|
||||
ps.execute();
|
||||
@@ -702,7 +701,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
Set<UUID> conflicting = new HashSet<>();
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_SELECT_ALL_UUIDS_BY_USERNAME))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_SELECT_ALL_UUIDS_BY_USERNAME))) {
|
||||
ps.setString(1, username);
|
||||
ps.setString(2, uniqueId.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
@@ -716,7 +715,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
if (!conflicting.isEmpty()) {
|
||||
// remove the mappings for conflicting uuids
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_DELETE_ALL_UUIDS_BY_USERNAME))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_DELETE_ALL_UUIDS_BY_USERNAME))) {
|
||||
ps.setString(1, username);
|
||||
ps.setString(2, uniqueId.toString());
|
||||
ps.execute();
|
||||
@@ -731,7 +730,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
@Override
|
||||
public void deletePlayerData(UUID uniqueId) throws SQLException {
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_DELETE))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_DELETE))) {
|
||||
ps.setString(1, uniqueId.toString());
|
||||
ps.execute();
|
||||
}
|
||||
@@ -742,7 +741,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
public UUID getPlayerUniqueId(String username) throws SQLException {
|
||||
username = username.toLowerCase(Locale.ROOT);
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_SELECT_UUID_BY_USERNAME))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_SELECT_UUID_BY_USERNAME))) {
|
||||
ps.setString(1, username);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
@@ -757,7 +756,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
@Override
|
||||
public String getPlayerName(UUID uniqueId) throws SQLException {
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_SELECT_USERNAME_BY_UUID))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_SELECT_USERNAME_BY_UUID))) {
|
||||
ps.setString(1, uniqueId.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
@@ -873,7 +872,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
}
|
||||
|
||||
if (!deleteRows.isEmpty()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(deleteSpecificQuery))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(deleteSpecificQuery))) {
|
||||
for (Long id : deleteRows) {
|
||||
ps.setLong(1, id);
|
||||
ps.addBatch();
|
||||
@@ -882,7 +881,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
}
|
||||
}
|
||||
if (!deleteNodes.isEmpty()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(deleteQuery))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(deleteQuery))) {
|
||||
for (Node node : deleteNodes) {
|
||||
ps.setString(1, holder);
|
||||
writeNode(node, ps);
|
||||
@@ -894,7 +893,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
}
|
||||
|
||||
if (!add.isEmpty()) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(insertQuery))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(insertQuery))) {
|
||||
for (Node node : add) {
|
||||
ps.setString(1, holder);
|
||||
writeNode(node, ps);
|
||||
@@ -907,7 +906,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
private List<Node> selectUserPermissions(Connection c, UUID user) throws SQLException {
|
||||
List<Node> nodes = new ArrayList<>();
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(USER_PERMISSIONS_SELECT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(USER_PERMISSIONS_SELECT))) {
|
||||
ps.setString(1, user.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
@@ -922,7 +921,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
}
|
||||
|
||||
private SqlPlayerData selectPlayerData(Connection c, UUID user) throws SQLException {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_SELECT_BY_UUID))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_SELECT_BY_UUID))) {
|
||||
ps.setString(1, user.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
@@ -983,15 +982,15 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
// we don't want to use preparedstatements because the parameter length is variable
|
||||
// safe to do string concat/replacement because the UUID.toString value isn't injectable
|
||||
return this.statementProcessor.process(baseQuery) + param;
|
||||
return this.statementProcessor.apply(baseQuery) + param;
|
||||
}
|
||||
|
||||
private void deleteUser(Connection c, UUID user) throws SQLException {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(USER_PERMISSIONS_DELETE))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(USER_PERMISSIONS_DELETE))) {
|
||||
ps.setString(1, user.toString());
|
||||
ps.execute();
|
||||
}
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_UPDATE_PRIMARY_GROUP_BY_UUID))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_UPDATE_PRIMARY_GROUP_BY_UUID))) {
|
||||
ps.setString(1, GroupManager.DEFAULT_GROUP_NAME);
|
||||
ps.setString(2, user.toString());
|
||||
ps.execute();
|
||||
@@ -1000,7 +999,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
private void insertPlayerData(Connection c, UUID user, SqlPlayerData data) throws SQLException {
|
||||
boolean hasPrimaryGroupSaved;
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_SELECT_PRIMARY_GROUP_BY_UUID))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_SELECT_PRIMARY_GROUP_BY_UUID))) {
|
||||
ps.setString(1, user.toString());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
hasPrimaryGroupSaved = rs.next();
|
||||
@@ -1009,14 +1008,14 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
if (hasPrimaryGroupSaved) {
|
||||
// update
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_UPDATE_PRIMARY_GROUP_BY_UUID))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_UPDATE_PRIMARY_GROUP_BY_UUID))) {
|
||||
ps.setString(1, data.primaryGroup);
|
||||
ps.setString(2, user.toString());
|
||||
ps.execute();
|
||||
}
|
||||
} else {
|
||||
// insert
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(PLAYER_INSERT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(PLAYER_INSERT))) {
|
||||
ps.setString(1, user.toString());
|
||||
ps.setString(2, data.username);
|
||||
ps.setString(3, data.primaryGroup);
|
||||
@@ -1027,7 +1026,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
private Set<String> selectGroups(Connection c) throws SQLException {
|
||||
Set<String> groups = new HashSet<>();
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(GROUP_SELECT_ALL))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(GROUP_SELECT_ALL))) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
groups.add(rs.getString("name").toLowerCase(Locale.ROOT));
|
||||
@@ -1039,7 +1038,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
private List<Node> selectGroupPermissions(Connection c, String group) throws SQLException {
|
||||
List<Node> nodes = new ArrayList<>();
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(GROUP_PERMISSIONS_SELECT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(GROUP_PERMISSIONS_SELECT))) {
|
||||
ps.setString(1, group);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
@@ -1054,7 +1053,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
}
|
||||
|
||||
private void selectAllGroupPermissions(Map<String, Collection<Node>> nodes, Connection c) throws SQLException {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(GROUP_PERMISSIONS_SELECT_ALL))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(GROUP_PERMISSIONS_SELECT_ALL))) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
String holder = rs.getString("name");
|
||||
@@ -1071,7 +1070,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
}
|
||||
|
||||
private void deleteGroupPermissions(Connection c, String group) throws SQLException {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(GROUP_PERMISSIONS_DELETE))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(GROUP_PERMISSIONS_DELETE))) {
|
||||
ps.setString(1, group);
|
||||
ps.execute();
|
||||
}
|
||||
@@ -1079,7 +1078,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
private List<String> selectTrack(Connection c, String name) throws SQLException {
|
||||
String groups;
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(TRACK_SELECT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(TRACK_SELECT))) {
|
||||
ps.setString(1, name);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.next()) {
|
||||
@@ -1094,7 +1093,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
private void insertTrack(Connection c, String name, List<String> groups) throws SQLException {
|
||||
String json = GsonProvider.normal().toJson(groups);
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(TRACK_INSERT))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(TRACK_INSERT))) {
|
||||
ps.setString(1, name);
|
||||
ps.setString(2, json);
|
||||
ps.execute();
|
||||
@@ -1103,7 +1102,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
private void updateTrack(Connection c, String name, List<String> groups) throws SQLException {
|
||||
String json = GsonProvider.normal().toJson(groups);
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(TRACK_UPDATE))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(TRACK_UPDATE))) {
|
||||
ps.setString(1, json);
|
||||
ps.setString(2, name);
|
||||
ps.execute();
|
||||
@@ -1112,7 +1111,7 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
private Set<String> selectTracks(Connection c) throws SQLException {
|
||||
Set<String> tracks = new HashSet<>();
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.process(TRACK_SELECT_ALL))) {
|
||||
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(TRACK_SELECT_ALL))) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
tracks.add(rs.getString("name").toLowerCase(Locale.ROOT));
|
||||
@@ -1122,14 +1121,15 @@ public class SqlStorage implements StorageImplementation {
|
||||
return tracks;
|
||||
}
|
||||
|
||||
private static List<String> listTables(Connection connection) throws SQLException {
|
||||
List<String> tables = new ArrayList<>();
|
||||
private static boolean tableExists(Connection connection, String table) throws SQLException {
|
||||
try (ResultSet rs = connection.getMetaData().getTables(connection.getCatalog(), null, "%", null)) {
|
||||
while (rs.next()) {
|
||||
tables.add(rs.getString(3).toLowerCase(Locale.ROOT));
|
||||
if (rs.getString(3).equalsIgnoreCase(table)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
|
||||
private static final class SqlPlayerData {
|
||||
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.storage.implementation.sql;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public interface StatementProcessor {
|
||||
|
||||
StatementProcessor USE_BACKTICKS = s -> s.replace('\'', '`');
|
||||
|
||||
StatementProcessor USE_DOUBLE_QUOTES = s -> s.replace('\'', '"');
|
||||
|
||||
String process(String statement);
|
||||
|
||||
default StatementProcessor compose(StatementProcessor before) {
|
||||
Objects.requireNonNull(before);
|
||||
return s -> process(before.process(s));
|
||||
}
|
||||
|
||||
}
|
||||
+3
-4
@@ -25,13 +25,12 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.implementation.sql.builder;
|
||||
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.StatementProcessor;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class PreparedStatementBuilder {
|
||||
private final StringBuilder sb = new StringBuilder();
|
||||
@@ -57,10 +56,10 @@ public class PreparedStatementBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public PreparedStatement build(Connection connection, StatementProcessor processor) throws SQLException {
|
||||
public PreparedStatement build(Connection connection, Function<String, String> mapping) throws SQLException {
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
statement = connection.prepareStatement(processor.process(this.sb.toString()));
|
||||
statement = connection.prepareStatement(mapping.apply(this.sb.toString()));
|
||||
for (int i = 0; i < this.variables.size(); i++) {
|
||||
String var = this.variables.get(i);
|
||||
statement.setString(i + 1, var);
|
||||
|
||||
+2
-2
@@ -27,10 +27,10 @@ package me.lucko.luckperms.common.storage.implementation.sql.connection;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.StorageMetadata;
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.StatementProcessor;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.function.Function;
|
||||
|
||||
public interface ConnectionFactory {
|
||||
|
||||
@@ -42,7 +42,7 @@ public interface ConnectionFactory {
|
||||
|
||||
StorageMetadata getMeta();
|
||||
|
||||
StatementProcessor getStatementProcessor();
|
||||
Function<String, String> getStatementProcessor();
|
||||
|
||||
Connection getConnection() throws SQLException;
|
||||
|
||||
|
||||
+6
-9
@@ -27,7 +27,6 @@ package me.lucko.luckperms.common.storage.implementation.sql.connection.file;
|
||||
|
||||
import me.lucko.luckperms.common.dependencies.Dependency;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.StatementProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -39,14 +38,9 @@ import java.sql.Statement;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class H2ConnectionFactory extends FlatfileConnectionFactory {
|
||||
public static final StatementProcessor STATEMENT_PROCESSOR = s -> s
|
||||
.replace('\'', '`')
|
||||
.replace("LIKE", "ILIKE")
|
||||
.replace("value", "`value`")
|
||||
.replace("``value``", "`value`");
|
||||
|
||||
private Constructor<?> connectionConstructor;
|
||||
|
||||
public H2ConnectionFactory(Path file) {
|
||||
@@ -97,8 +91,11 @@ public class H2ConnectionFactory extends FlatfileConnectionFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementProcessor getStatementProcessor() {
|
||||
return STATEMENT_PROCESSOR;
|
||||
public Function<String, String> getStatementProcessor() {
|
||||
return s -> s.replace('\'', '`')
|
||||
.replace("LIKE", "ILIKE")
|
||||
.replace("value", "`value`")
|
||||
.replace("``value``", "`value`");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -27,7 +27,6 @@ package me.lucko.luckperms.common.storage.implementation.sql.connection.file;
|
||||
|
||||
import me.lucko.luckperms.common.dependencies.Dependency;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.StatementProcessor;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.nio.file.Path;
|
||||
@@ -35,6 +34,7 @@ import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class SqliteConnectionFactory extends FlatfileConnectionFactory {
|
||||
private Constructor<?> connectionConstructor;
|
||||
@@ -74,7 +74,7 @@ public class SqliteConnectionFactory extends FlatfileConnectionFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementProcessor getStatementProcessor() {
|
||||
return StatementProcessor.USE_BACKTICKS;
|
||||
public Function<String, String> getStatementProcessor() {
|
||||
return s -> s.replace('\'', '`');
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -25,9 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.implementation.sql.connection.hikari;
|
||||
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.StatementProcessor;
|
||||
import me.lucko.luckperms.common.storage.misc.StorageCredentials;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class MariaDbConnectionFactory extends DriverBasedHikariConnectionFactory {
|
||||
public MariaDbConnectionFactory(StorageCredentials configuration) {
|
||||
super(configuration);
|
||||
@@ -54,7 +55,7 @@ public class MariaDbConnectionFactory extends DriverBasedHikariConnectionFactory
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementProcessor getStatementProcessor() {
|
||||
return StatementProcessor.USE_BACKTICKS;
|
||||
public Function<String, String> getStatementProcessor() {
|
||||
return s -> s.replace('\'', '`'); // use backticks for quotes
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -25,10 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.implementation.sql.connection.hikari;
|
||||
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.StatementProcessor;
|
||||
import me.lucko.luckperms.common.storage.misc.StorageCredentials;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class MySqlConnectionFactory extends DriverBasedHikariConnectionFactory {
|
||||
public MySqlConnectionFactory(StorageCredentials configuration) {
|
||||
@@ -80,7 +80,7 @@ public class MySqlConnectionFactory extends DriverBasedHikariConnectionFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementProcessor getStatementProcessor() {
|
||||
return StatementProcessor.USE_BACKTICKS;
|
||||
public Function<String, String> getStatementProcessor() {
|
||||
return s -> s.replace('\'', '`'); // use backticks for quotes
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -25,10 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.storage.implementation.sql.connection.hikari;
|
||||
|
||||
import me.lucko.luckperms.common.storage.implementation.sql.StatementProcessor;
|
||||
import me.lucko.luckperms.common.storage.misc.StorageCredentials;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class PostgresConnectionFactory extends DriverBasedHikariConnectionFactory {
|
||||
public PostgresConnectionFactory(StorageCredentials configuration) {
|
||||
@@ -65,7 +65,7 @@ public class PostgresConnectionFactory extends DriverBasedHikariConnectionFactor
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementProcessor getStatementProcessor() {
|
||||
return StatementProcessor.USE_DOUBLE_QUOTES;
|
||||
public Function<String, String> getStatementProcessor() {
|
||||
return s -> s.replace('\'', '"');
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.treeview;
|
||||
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerTask;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class AsyncPermissionRegistry extends PermissionRegistry implements AutoCloseable {
|
||||
|
||||
/** A queue of permission strings to be added to the tree */
|
||||
private final Queue<String> queue;
|
||||
/** The tick task */
|
||||
private final SchedulerTask task;
|
||||
|
||||
public AsyncPermissionRegistry(SchedulerAdapter scheduler) {
|
||||
this.queue = new ConcurrentLinkedQueue<>();
|
||||
this.task = scheduler.asyncRepeating(this::tick, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offer(String permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
this.queue.offer(permission);
|
||||
}
|
||||
|
||||
private void tick() {
|
||||
for (String e; (e = this.queue.poll()) != null; ) {
|
||||
try {
|
||||
doInsert(e);
|
||||
} catch (Exception ex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.task.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,20 +26,35 @@
|
||||
package me.lucko.luckperms.common.treeview;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerAdapter;
|
||||
import me.lucko.luckperms.common.plugin.scheduler.SchedulerTask;
|
||||
import me.lucko.luckperms.common.util.ImmutableCollectors;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Stores a collection of all permissions known to the platform.
|
||||
*/
|
||||
public class PermissionRegistry {
|
||||
public class PermissionRegistry implements AutoCloseable {
|
||||
private static final Splitter DOT_SPLIT = Splitter.on('.').omitEmptyStrings();
|
||||
|
||||
/** The root node in the tree */
|
||||
private final TreeNode rootNode = new TreeNode();
|
||||
private final TreeNode rootNode;
|
||||
/** A queue of permission strings to be added to the tree */
|
||||
private final Queue<String> queue;
|
||||
/** The tick task */
|
||||
private final SchedulerTask task;
|
||||
|
||||
public PermissionRegistry(SchedulerAdapter scheduler) {
|
||||
this.rootNode = new TreeNode();
|
||||
this.queue = new ConcurrentLinkedQueue<>();
|
||||
this.task = scheduler.asyncRepeating(this::tick, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public TreeNode getRootNode() {
|
||||
return this.rootNode;
|
||||
@@ -51,33 +66,33 @@ public class PermissionRegistry {
|
||||
.collect(ImmutableCollectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Offer a permission to the registry (to be potentially inserted asynchronously).
|
||||
*
|
||||
* @param permission the permission
|
||||
*/
|
||||
public void offer(String permission) {
|
||||
insert(permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a permission into the registry.
|
||||
*
|
||||
* @param permission the permission
|
||||
*/
|
||||
public void insert(String permission) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
this.queue.offer(permission);
|
||||
}
|
||||
|
||||
try {
|
||||
doInsert(permission);
|
||||
} catch (Exception ex) {
|
||||
// ignore
|
||||
private void tick() {
|
||||
for (String e; (e = this.queue.poll()) != null; ) {
|
||||
insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doInsert(String permission) {
|
||||
@Override
|
||||
public void close() {
|
||||
this.task.cancel();
|
||||
}
|
||||
|
||||
public void insert(String permission) {
|
||||
try {
|
||||
doInsert(permission);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void doInsert(String permission) {
|
||||
permission = permission.toLowerCase(Locale.ROOT);
|
||||
|
||||
// split the permission up into parts
|
||||
|
||||
@@ -29,7 +29,7 @@ import me.lucko.luckperms.common.locale.TranslationManager;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
@@ -72,7 +72,7 @@ public class DurationFormatter {
|
||||
* @return the formatted string
|
||||
*/
|
||||
public String formatString(Duration duration) {
|
||||
return PlainTextComponentSerializer.plainText().serialize(TranslationManager.render(format(duration)));
|
||||
return PlainComponentSerializer.plain().serialize(TranslationManager.render(format(duration)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,21 +25,36 @@
|
||||
|
||||
package me.lucko.luckperms.common.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class ExpiringSet {
|
||||
private ExpiringSet() {}
|
||||
/**
|
||||
* A simple expiring set implementation using Caffeine caches
|
||||
*
|
||||
* @param <E> element type
|
||||
*/
|
||||
public class ExpiringSet<E> {
|
||||
private final Cache<E, Long> cache;
|
||||
private final long lifetime;
|
||||
|
||||
/**
|
||||
* An expiring set using Caffeine caches
|
||||
*
|
||||
* @param <E> the element type
|
||||
* @return a new expiring set
|
||||
*/
|
||||
public static <E> Set<E> newExpiringSet(long duration, TimeUnit unit) {
|
||||
return Collections.newSetFromMap(CaffeineFactory.newBuilder().expireAfterWrite(duration, unit).<E, Boolean>build().asMap());
|
||||
public ExpiringSet(long duration, TimeUnit unit) {
|
||||
this.cache = CaffeineFactory.newBuilder().expireAfterWrite(duration, unit).build();
|
||||
this.lifetime = unit.toMillis(duration);
|
||||
}
|
||||
|
||||
public boolean add(E item) {
|
||||
boolean present = contains(item);
|
||||
this.cache.put(item, System.currentTimeMillis() + this.lifetime);
|
||||
return !present;
|
||||
}
|
||||
|
||||
public boolean contains(E item) {
|
||||
Long timeout = this.cache.getIfPresent(item);
|
||||
return timeout != null && timeout > System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void remove(E item) {
|
||||
this.cache.invalidate(item);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,6 @@ import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.VerboseEvent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
@@ -223,7 +222,7 @@ public class VerboseListener {
|
||||
}
|
||||
|
||||
// send the message
|
||||
HoverEvent<Component> hoverEvent = HoverEvent.showText(Component.join(JoinConfiguration.newlines(), hover));
|
||||
HoverEvent<Component> hoverEvent = HoverEvent.showText(Component.join(Component.newline(), hover));
|
||||
this.notifiedSender.sendMessage(component.hoverEvent(hoverEvent));
|
||||
}
|
||||
|
||||
|
||||
+18
-71
@@ -32,75 +32,14 @@ import java.security.KeyPairGenerator;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Signature;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* The signature algorithm & public/private key crypto logic used by the web editor socket connection.
|
||||
* Utilities for public/private key crypto used by the web editor socket connection.
|
||||
*/
|
||||
public enum SignatureAlgorithm {
|
||||
V1_RSA(1, "RSA", "SHA256withRSA") {
|
||||
@Override
|
||||
public KeyPair generateKeyPair() {
|
||||
try {
|
||||
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
|
||||
generator.initialize(4096);
|
||||
return generator.generateKeyPair();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Exception generating keypair", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
V2_ECDSA(2, "EC", "SHA256withECDSAinP1363Format") {
|
||||
@Override
|
||||
public KeyPair generateKeyPair() {
|
||||
try {
|
||||
KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
|
||||
generator.initialize(new ECGenParameterSpec("secp256r1"));
|
||||
return generator.generateKeyPair();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Exception generating keypair", e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The selected {@link SignatureAlgorithm} for the current environment.
|
||||
*/
|
||||
public static final SignatureAlgorithm INSTANCE;
|
||||
|
||||
static {
|
||||
// select an instance to use based on the available algorithms
|
||||
SignatureAlgorithm instance = V1_RSA;
|
||||
try {
|
||||
KeyPairGenerator.getInstance(V2_ECDSA.keyFactoryAlgorithm);
|
||||
Signature.getInstance(V2_ECDSA.signatureAlgorithm);
|
||||
instance = V2_ECDSA;
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
INSTANCE = instance;
|
||||
}
|
||||
|
||||
private final int protocolVersion;
|
||||
private final String keyFactoryAlgorithm;
|
||||
private final String signatureAlgorithm;
|
||||
|
||||
SignatureAlgorithm(int protocolVersion, String keyFactoryAlgorithm, String signatureAlgorithm) {
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.keyFactoryAlgorithm = keyFactoryAlgorithm;
|
||||
this.signatureAlgorithm = signatureAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the corresponding protocol version
|
||||
*
|
||||
* @return the protocol version
|
||||
*/
|
||||
public int protocolVersion() {
|
||||
return this.protocolVersion;
|
||||
}
|
||||
public final class CryptographyUtils {
|
||||
private CryptographyUtils() {}
|
||||
|
||||
/**
|
||||
* Parse a public key from the given string.
|
||||
@@ -109,11 +48,11 @@ public enum SignatureAlgorithm {
|
||||
* @return the parsed public key
|
||||
* @throws IllegalArgumentException if the input was invalid
|
||||
*/
|
||||
public PublicKey parsePublicKey(String base64String) throws IllegalArgumentException {
|
||||
public static PublicKey parsePublicKey(String base64String) throws IllegalArgumentException {
|
||||
try {
|
||||
byte[] bytes = Base64.getDecoder().decode(base64String);
|
||||
X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
|
||||
KeyFactory rsa = KeyFactory.getInstance(this.keyFactoryAlgorithm);
|
||||
KeyFactory rsa = KeyFactory.getInstance("RSA");
|
||||
return rsa.generatePublic(spec);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Exception parsing public key", e);
|
||||
@@ -125,7 +64,15 @@ public enum SignatureAlgorithm {
|
||||
*
|
||||
* @return the generated key pair
|
||||
*/
|
||||
public abstract KeyPair generateKeyPair();
|
||||
public static KeyPair generateKeyPair() {
|
||||
try {
|
||||
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
|
||||
generator.initialize(4096);
|
||||
return generator.generateKeyPair();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Exception generating keypair", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs {@code msg} using the given {@link PrivateKey}.
|
||||
@@ -134,9 +81,9 @@ public enum SignatureAlgorithm {
|
||||
* @param msg the message
|
||||
* @return a base64 string containing the signature
|
||||
*/
|
||||
public String sign(PrivateKey privateKey, String msg) {
|
||||
public static String sign(PrivateKey privateKey, String msg) {
|
||||
try {
|
||||
Signature sign = Signature.getInstance(this.signatureAlgorithm);
|
||||
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||
sign.initSign(privateKey);
|
||||
sign.update(msg.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
@@ -155,9 +102,9 @@ public enum SignatureAlgorithm {
|
||||
* @param signatureBase64 the provided signature
|
||||
* @return true if the signature is ok
|
||||
*/
|
||||
public boolean verify(PublicKey publicKey, String msg, String signatureBase64) {
|
||||
public static boolean verify(PublicKey publicKey, String msg, String signatureBase64) {
|
||||
try {
|
||||
Signature sign = Signature.getInstance(this.signatureAlgorithm);
|
||||
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||
sign.initVerify(publicKey);
|
||||
sign.update(msg.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
+4
-2
@@ -47,6 +47,8 @@ import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class WebEditorSocket {
|
||||
|
||||
private static final int PROTOCOL_VERSION = 1;
|
||||
|
||||
/** The plugin */
|
||||
private final LuckPermsPlugin plugin;
|
||||
/** The sender who created the editor session */
|
||||
@@ -112,7 +114,7 @@ public class WebEditorSocket {
|
||||
String publicKey = Base64.getEncoder().encodeToString(this.pluginKeyPair.getPublic().getEncoded());
|
||||
|
||||
JsonObject socket = new JsonObject();
|
||||
socket.addProperty("protocolVersion", SignatureAlgorithm.INSTANCE.protocolVersion());
|
||||
socket.addProperty("protocolVersion", PROTOCOL_VERSION);
|
||||
socket.addProperty("channelId", channelId);
|
||||
socket.addProperty("publicKey", publicKey);
|
||||
|
||||
@@ -130,7 +132,7 @@ public class WebEditorSocket {
|
||||
*/
|
||||
public void send(JsonObject msg) {
|
||||
String encoded = GsonProvider.normal().toJson(msg);
|
||||
String signature = SignatureAlgorithm.INSTANCE.sign(this.pluginKeyPair.getPrivate(), encoded);
|
||||
String signature = CryptographyUtils.sign(this.pluginKeyPair.getPrivate(), encoded);
|
||||
|
||||
JsonObject frame = new JObject()
|
||||
.add("msg", encoded)
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@ package me.lucko.luckperms.common.webeditor.socket.listener;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.webeditor.socket.SignatureAlgorithm;
|
||||
import me.lucko.luckperms.common.webeditor.socket.CryptographyUtils;
|
||||
import me.lucko.luckperms.common.webeditor.socket.SocketMessageType;
|
||||
import me.lucko.luckperms.common.webeditor.socket.WebEditorSocket;
|
||||
import me.lucko.luckperms.common.webeditor.store.RemoteSession;
|
||||
@@ -73,7 +73,7 @@ public class HandlerHello implements Handler {
|
||||
String nonce = getStringOrThrow(msg, "nonce");
|
||||
String sessionId = getStringOrThrow(msg, "sessionId");
|
||||
String browser = msg.get("browser").getAsString();
|
||||
PublicKey remotePublicKey = SignatureAlgorithm.INSTANCE.parsePublicKey(msg.get("publicKey").getAsString());
|
||||
PublicKey remotePublicKey = CryptographyUtils.parsePublicKey(msg.get("publicKey").getAsString());
|
||||
|
||||
// check if the public keys are the same
|
||||
// (this allows the same editor to re-connect, but prevents new connections)
|
||||
|
||||
+2
-2
@@ -27,7 +27,7 @@ package me.lucko.luckperms.common.webeditor.socket.listener;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import me.lucko.luckperms.common.util.gson.GsonProvider;
|
||||
import me.lucko.luckperms.common.webeditor.socket.SignatureAlgorithm;
|
||||
import me.lucko.luckperms.common.webeditor.socket.CryptographyUtils;
|
||||
import me.lucko.luckperms.common.webeditor.socket.SocketMessageType;
|
||||
import me.lucko.luckperms.common.webeditor.socket.WebEditorSocket;
|
||||
import okhttp3.Response;
|
||||
@@ -126,7 +126,7 @@ public class WebEditorSocketListener extends WebSocketListener {
|
||||
|
||||
// check signature to ensure the message is from the connected editor
|
||||
PublicKey remotePublicKey = this.socket.getRemotePublicKey();
|
||||
boolean verified = remotePublicKey != null && SignatureAlgorithm.INSTANCE.verify(remotePublicKey, innerMsg, signature);
|
||||
boolean verified = remotePublicKey != null && CryptographyUtils.verify(remotePublicKey, innerMsg, signature);
|
||||
|
||||
// parse the inner message
|
||||
JsonObject msg = GsonProvider.parser().parse(innerMsg).getAsJsonObject();
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.webeditor.socket.SignatureAlgorithm;
|
||||
import me.lucko.luckperms.common.webeditor.socket.CryptographyUtils;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -51,7 +51,7 @@ public class WebEditorStore {
|
||||
this.keystore = new WebEditorKeystore(plugin.getBootstrap().getConfigDirectory().resolve("editor-keystore.json"));
|
||||
|
||||
Supplier<CompletableFuture<KeyPair>> keyPair = () -> CompletableFuture.supplyAsync(
|
||||
SignatureAlgorithm.INSTANCE::generateKeyPair,
|
||||
CryptographyUtils::generateKeyPair,
|
||||
plugin.getBootstrap().getScheduler().async()
|
||||
);
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ luckperms.commandsystem.command-not-recognised=Command not recognised
|
||||
luckperms.commandsystem.no-permission=You do not have permission to use this command!
|
||||
luckperms.commandsystem.no-permission-subcommands=You do not have permission to use any sub commands
|
||||
luckperms.commandsystem.already-executing-command=Another command is being executed, waiting for it to finish...
|
||||
luckperms.commandsystem.commands-disabled=LuckPerms commands are disabled
|
||||
luckperms.commandsystem.usage.sub-commands-header=Sub Commands
|
||||
luckperms.commandsystem.usage.usage-header=Command Usage
|
||||
luckperms.commandsystem.usage.arguments-header=Arguments
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.StandardStackElements;
|
||||
import me.lucko.luckperms.common.cacheddata.result.IntegerResult;
|
||||
import me.lucko.luckperms.common.cacheddata.result.StringResult;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaAccumulator;
|
||||
import me.lucko.luckperms.common.node.types.DisplayName;
|
||||
import me.lucko.luckperms.common.node.types.Meta;
|
||||
import me.lucko.luckperms.common.node.types.Prefix;
|
||||
import me.lucko.luckperms.common.node.types.Suffix;
|
||||
import me.lucko.luckperms.common.node.types.Weight;
|
||||
import net.luckperms.api.metastacking.DuplicateRemovalFunction;
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import net.luckperms.api.node.types.SuffixNode;
|
||||
import net.luckperms.api.node.types.WeightNode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
|
||||
import org.testcontainers.shaded.com.google.common.collect.ImmutableSet;
|
||||
|
||||
import java.util.SortedMap;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class MetaAccumulatorTest {
|
||||
|
||||
@Test
|
||||
public void testStates() {
|
||||
SimpleMetaStackDefinition definition = new SimpleMetaStackDefinition(ImmutableList.of(StandardStackElements.HIGHEST), DuplicateRemovalFunction.RETAIN_ALL, "", "", "");
|
||||
MetaAccumulator accumulator = new MetaAccumulator(definition, definition);
|
||||
|
||||
assertThrows(IllegalStateException.class, accumulator::getMeta);
|
||||
assertThrows(IllegalStateException.class, () -> accumulator.getChatMeta(ChatMetaType.PREFIX));
|
||||
assertThrows(IllegalStateException.class, accumulator::getPrefixes);
|
||||
assertThrows(IllegalStateException.class, accumulator::getSuffixes);
|
||||
assertThrows(IllegalStateException.class, accumulator::getWeight);
|
||||
assertThrows(IllegalStateException.class, accumulator::getPrimaryGroup);
|
||||
assertThrows(IllegalStateException.class, accumulator::getPrefixDefinition);
|
||||
assertThrows(IllegalStateException.class, accumulator::getSuffixDefinition);
|
||||
assertThrows(IllegalStateException.class, accumulator::getPrefix);
|
||||
assertThrows(IllegalStateException.class, accumulator::getSuffix);
|
||||
|
||||
Prefix prefixNode = Prefix.builder("hello", 100).build();
|
||||
|
||||
accumulator.accumulateNode(prefixNode);
|
||||
accumulator.complete();
|
||||
|
||||
assertThrows(IllegalStateException.class, () -> accumulator.accumulateNode(prefixNode));
|
||||
|
||||
StringResult<PrefixNode> prefixResult = accumulator.getPrefix();
|
||||
assertEquals(prefixNode, prefixResult.node());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
SimpleMetaStackDefinition definition = new SimpleMetaStackDefinition(ImmutableList.of(StandardStackElements.HIGHEST), DuplicateRemovalFunction.RETAIN_ALL, "[", "|", "]");
|
||||
MetaAccumulator accumulator = new MetaAccumulator(definition, definition);
|
||||
accumulator.complete();
|
||||
|
||||
ListMultimap<String, StringResult<MetaNode>> meta = accumulator.getMeta();
|
||||
assertEquals(0, meta.size());
|
||||
|
||||
SortedMap<Integer, StringResult<PrefixNode>> prefixes = accumulator.getPrefixes();
|
||||
assertEquals(0, prefixes.size());
|
||||
|
||||
SortedMap<Integer, StringResult<SuffixNode>> suffixes = accumulator.getSuffixes();
|
||||
assertEquals(0, suffixes.size());
|
||||
|
||||
IntegerResult<WeightNode> weight = accumulator.getWeight();
|
||||
assertTrue(weight.isNull());
|
||||
assertEquals(0, weight.intResult());
|
||||
assertNull(weight.node());
|
||||
|
||||
String primaryGroup = accumulator.getPrimaryGroup();
|
||||
assertNull(primaryGroup);
|
||||
|
||||
MetaStackDefinition prefixDefinition = accumulator.getPrefixDefinition();
|
||||
assertSame(definition, prefixDefinition);
|
||||
|
||||
MetaStackDefinition suffixDefinition = accumulator.getSuffixDefinition();
|
||||
assertSame(definition, suffixDefinition);
|
||||
|
||||
StringResult<PrefixNode> prefix = accumulator.getPrefix();
|
||||
assertNull(prefix.result());
|
||||
assertNull(prefix.node());
|
||||
|
||||
StringResult<SuffixNode> suffix = accumulator.getSuffix();
|
||||
assertNull(suffix.result());
|
||||
assertNull(suffix.node());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimple() {
|
||||
SimpleMetaStackDefinition definition = new SimpleMetaStackDefinition(ImmutableList.of(StandardStackElements.HIGHEST), DuplicateRemovalFunction.RETAIN_ALL, "[", "|", "]");
|
||||
MetaAccumulator accumulator = new MetaAccumulator(definition, definition);
|
||||
|
||||
accumulator.accumulateNode(Prefix.builder("b", 90).build());
|
||||
accumulator.accumulateNode(Prefix.builder("a", 100).build());
|
||||
accumulator.accumulateNode(Prefix.builder("c", 80).build());
|
||||
accumulator.accumulateNode(Suffix.builder("foo", 80).build());
|
||||
accumulator.accumulateNode(Meta.builder().key("foo").value("bar").build());
|
||||
accumulator.accumulateNode(Weight.builder(10).build()); // ignored
|
||||
accumulator.accumulateNode(DisplayName.builder("hello").build());
|
||||
accumulator.accumulateWeight(IntegerResult.of(Weight.builder(5).build()));
|
||||
accumulator.setPrimaryGroup("member");
|
||||
|
||||
accumulator.complete();
|
||||
|
||||
StringResult<PrefixNode> prefix = accumulator.getPrefix();
|
||||
assertEquals("[a]", prefix.result());
|
||||
|
||||
SortedMap<Integer, StringResult<PrefixNode>> prefixes = accumulator.getPrefixes();
|
||||
assertEquals(ImmutableSet.of(100, 90, 80), prefixes.keySet());
|
||||
|
||||
StringResult<SuffixNode> suffix = accumulator.getSuffix();
|
||||
assertEquals("[foo]", suffix.result());
|
||||
|
||||
SortedMap<Integer, StringResult<SuffixNode>> suffixes = accumulator.getSuffixes();
|
||||
assertEquals(ImmutableSet.of(80), suffixes.keySet());
|
||||
|
||||
ListMultimap<String, StringResult<MetaNode>> meta = accumulator.getMeta();
|
||||
assertEquals(3, meta.size());
|
||||
assertEquals(ImmutableSet.of("foo", "weight", "primarygroup"), meta.keySet());
|
||||
assertEquals("bar", meta.get("foo").get(0).result());
|
||||
assertEquals("5", meta.get("weight").get(0).result());
|
||||
assertEquals("member", meta.get("primarygroup").get(0).result());
|
||||
|
||||
IntegerResult<WeightNode> weight = accumulator.getWeight();
|
||||
assertEquals(5, weight.intResult());
|
||||
|
||||
String primaryGroup = accumulator.getPrimaryGroup();
|
||||
assertEquals("member", primaryGroup);
|
||||
}
|
||||
|
||||
}
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.StandardStackElements;
|
||||
import me.lucko.luckperms.common.cacheddata.result.StringResult;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaStackAccumulator;
|
||||
import me.lucko.luckperms.common.node.types.Prefix;
|
||||
import net.luckperms.api.metastacking.DuplicateRemovalFunction;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
public class MetaStackAccumulatorTest {
|
||||
|
||||
@Test
|
||||
public void testEmpty() {
|
||||
SimpleMetaStackDefinition definition = new SimpleMetaStackDefinition(ImmutableList.of(StandardStackElements.HIGHEST), DuplicateRemovalFunction.RETAIN_ALL, "", "", "");
|
||||
MetaStackAccumulator<PrefixNode> accumulator = new MetaStackAccumulator<>(definition, ChatMetaType.PREFIX);
|
||||
|
||||
StringResult<PrefixNode> result = accumulator.toResult();
|
||||
assertNotNull(result);
|
||||
assertNull(result.result());
|
||||
assertNull(result.node());
|
||||
assertNull(result.overriddenResult());
|
||||
|
||||
String formattedString = accumulator.toFormattedString();
|
||||
assertNull(formattedString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingle() {
|
||||
SimpleMetaStackDefinition definition = new SimpleMetaStackDefinition(ImmutableList.of(StandardStackElements.HIGHEST), DuplicateRemovalFunction.RETAIN_ALL, "[", "|", "]");
|
||||
MetaStackAccumulator<PrefixNode> accumulator = new MetaStackAccumulator<>(definition, ChatMetaType.PREFIX);
|
||||
|
||||
PrefixNode a = Prefix.builder("a", 100).build();
|
||||
PrefixNode b = Prefix.builder("b", 90).build();
|
||||
PrefixNode c = Prefix.builder("c", 80).build();
|
||||
|
||||
accumulator.offer(b);
|
||||
accumulator.offer(a);
|
||||
accumulator.offer(c);
|
||||
|
||||
StringResult<PrefixNode> result = accumulator.toResult();
|
||||
assertNotNull(result);
|
||||
assertEquals("[a]", result.result());
|
||||
assertEquals(a, result.node());
|
||||
assertNull(result.overriddenResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiple() {
|
||||
SimpleMetaStackDefinition definition = new SimpleMetaStackDefinition(ImmutableList.of(StandardStackElements.LOWEST, StandardStackElements.HIGHEST), DuplicateRemovalFunction.RETAIN_ALL, "[", "|", "]");
|
||||
MetaStackAccumulator<PrefixNode> accumulator = new MetaStackAccumulator<>(definition, ChatMetaType.PREFIX);
|
||||
|
||||
PrefixNode a = Prefix.builder("a", 100).build();
|
||||
PrefixNode b = Prefix.builder("b", 90).build();
|
||||
PrefixNode c = Prefix.builder("c", 80).build();
|
||||
|
||||
accumulator.offer(b);
|
||||
accumulator.offer(a);
|
||||
accumulator.offer(c);
|
||||
|
||||
StringResult<PrefixNode> result = accumulator.toResult();
|
||||
assertNotNull(result);
|
||||
assertEquals("[c|a]", result.result());
|
||||
assertEquals(c, result.node());
|
||||
|
||||
StringResult<PrefixNode> overriddenResult = result.overriddenResult();
|
||||
assertNotNull(overriddenResult);
|
||||
assertEquals(a, overriddenResult.node());
|
||||
assertNull(overriddenResult.overriddenResult());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.StandardStackElements;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.model.InheritanceOrigin;
|
||||
import me.lucko.luckperms.common.model.PermissionHolderIdentifier;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.model.manager.track.StandardTrackManager;
|
||||
import me.lucko.luckperms.common.model.manager.track.TrackManager;
|
||||
import me.lucko.luckperms.common.node.types.Prefix;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import net.luckperms.api.metastacking.MetaStackElement;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.metadata.types.InheritanceOriginMetadata;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class MetaStackElementTest {
|
||||
|
||||
@Test
|
||||
public void testHighest() {
|
||||
MetaStackElement highest = StandardStackElements.HIGHEST;
|
||||
assertTrue(highest.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(highest.shouldAccumulate(
|
||||
ChatMetaType.SUFFIX,
|
||||
Prefix.builder("foo", 100).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertTrue(highest.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).build(), // node
|
||||
Prefix.builder("bar", 50).build()) // current
|
||||
);
|
||||
assertFalse(highest.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 50).build(), // node
|
||||
Prefix.builder("bar", 100).build()) // current
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLowest() {
|
||||
MetaStackElement lowest = StandardStackElements.LOWEST;
|
||||
assertTrue(lowest.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(lowest.shouldAccumulate(
|
||||
ChatMetaType.SUFFIX,
|
||||
Prefix.builder("foo", 100).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertTrue(lowest.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 50).build(), // node
|
||||
Prefix.builder("bar", 100).build()) // current
|
||||
);
|
||||
assertFalse(lowest.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).build(), // node
|
||||
Prefix.builder("bar", 50).build()) // current
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighestOwn() {
|
||||
InheritanceOrigin userOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.USER, ""), DataType.NORMAL);
|
||||
InheritanceOrigin groupOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, ""), DataType.NORMAL);
|
||||
|
||||
MetaStackElement highestOwn = StandardStackElements.HIGHEST_OWN;
|
||||
assertTrue(highestOwn.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, userOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(highestOwn.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, groupOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighestInherited() {
|
||||
InheritanceOrigin userOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.USER, ""), DataType.NORMAL);
|
||||
InheritanceOrigin groupOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, ""), DataType.NORMAL);
|
||||
|
||||
MetaStackElement highestInherited = StandardStackElements.HIGHEST_INHERITED;
|
||||
assertTrue(highestInherited.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, groupOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(highestInherited.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, userOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Test
|
||||
public void testHighestFromGroupOnTrack() {
|
||||
LuckPermsPlugin plugin = mock(LuckPermsPlugin.class);
|
||||
TrackManager<Track> trackManager = new StandardTrackManager(plugin);
|
||||
when(plugin.getTrackManager()).thenReturn((TrackManager) trackManager);
|
||||
|
||||
Track track = trackManager.getOrMake("test");
|
||||
track.setGroups(ImmutableList.of("foo", "bar"));
|
||||
|
||||
InheritanceOrigin fooOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, "foo"), DataType.NORMAL);
|
||||
InheritanceOrigin bazOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, "baz"), DataType.NORMAL);
|
||||
|
||||
MetaStackElement highestFromGroupOnTrack = StandardStackElements.highestFromGroupOnTrack(plugin, "test");
|
||||
assertTrue(highestFromGroupOnTrack.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, fooOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(highestFromGroupOnTrack.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, bazOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Test
|
||||
public void testHighestNotFromGroupOnTrack() {
|
||||
LuckPermsPlugin plugin = mock(LuckPermsPlugin.class);
|
||||
TrackManager<Track> trackManager = new StandardTrackManager(plugin);
|
||||
when(plugin.getTrackManager()).thenReturn((TrackManager) trackManager);
|
||||
|
||||
Track track = trackManager.getOrMake("test");
|
||||
track.setGroups(ImmutableList.of("foo", "bar"));
|
||||
|
||||
InheritanceOrigin fooOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, "foo"), DataType.NORMAL);
|
||||
InheritanceOrigin bazOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, "baz"), DataType.NORMAL);
|
||||
InheritanceOrigin userOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.USER, "foo"), DataType.NORMAL);
|
||||
|
||||
MetaStackElement highestNotFromGroupOnTrack = StandardStackElements.highestNotFromGroupOnTrack(plugin, "test");
|
||||
assertTrue(highestNotFromGroupOnTrack.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, userOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertTrue(highestNotFromGroupOnTrack.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, bazOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(highestNotFromGroupOnTrack.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, fooOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighestFromGroup() {
|
||||
InheritanceOrigin fooOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, "foo"), DataType.NORMAL);
|
||||
InheritanceOrigin bazOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, "baz"), DataType.NORMAL);
|
||||
InheritanceOrigin userOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.USER, "foo"), DataType.NORMAL);
|
||||
|
||||
MetaStackElement highestFromGroup = StandardStackElements.highestFromGroup("foo");
|
||||
assertTrue(highestFromGroup.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, fooOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(highestFromGroup.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, bazOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(highestFromGroup.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, userOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHighestNotFromGroup() {
|
||||
InheritanceOrigin fooOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, "foo"), DataType.NORMAL);
|
||||
InheritanceOrigin bazOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.GROUP, "baz"), DataType.NORMAL);
|
||||
InheritanceOrigin userOrigin = new InheritanceOrigin(new PermissionHolderIdentifier(HolderType.USER, "foo"), DataType.NORMAL);
|
||||
|
||||
MetaStackElement highestNotFromGroup = StandardStackElements.highestNotFromGroup("foo");
|
||||
assertTrue(highestNotFromGroup.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, userOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertTrue(highestNotFromGroup.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, bazOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
assertFalse(highestNotFromGroup.shouldAccumulate(
|
||||
ChatMetaType.PREFIX,
|
||||
Prefix.builder("foo", 100).withMetadata(InheritanceOriginMetadata.KEY, fooOrigin).build(), // node
|
||||
null // current
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import me.lucko.luckperms.common.cacheddata.result.StringResult;
|
||||
import me.lucko.luckperms.common.cacheddata.type.SimpleMetaValueSelector;
|
||||
import me.lucko.luckperms.common.cacheddata.type.SimpleMetaValueSelector.Strategy;
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class MetaValueSelectorTest {
|
||||
|
||||
@Test
|
||||
public void testStrategies() {
|
||||
Map<String, Strategy> strategies = ImmutableMap.of(
|
||||
"foo", Strategy.HIGHEST_NUMBER,
|
||||
"bar", Strategy.LOWEST_NUMBER
|
||||
);
|
||||
SimpleMetaValueSelector selector = new SimpleMetaValueSelector(strategies, Strategy.INHERITANCE);
|
||||
|
||||
// empty
|
||||
assertThrows(IllegalArgumentException.class, () -> selector.selectValue("hello", ImmutableList.of()));
|
||||
|
||||
Result<String, MetaNode> foo = StringResult.of("foo");
|
||||
|
||||
// single value
|
||||
Result<String, MetaNode> value = selector.selectValue("abc", ImmutableList.of(foo));
|
||||
assertSame(foo, value);
|
||||
|
||||
// fallback to default when values are not numbers
|
||||
value = selector.selectValue("foo", ImmutableList.of(foo));
|
||||
assertSame(foo, value);
|
||||
|
||||
Result<String, MetaNode> one = StringResult.of("1");
|
||||
Result<String, MetaNode> two = StringResult.of("2");
|
||||
Result<String, MetaNode> three = StringResult.of("3");
|
||||
ImmutableList<Result<String, MetaNode>> values = ImmutableList.of(two, one, three);
|
||||
|
||||
// first value
|
||||
assertSame(two, selector.selectValue("abc", values));
|
||||
|
||||
// highest value
|
||||
assertSame(three, selector.selectValue("foo", values));
|
||||
|
||||
// lowest value
|
||||
assertSame(one, selector.selectValue("bar", values));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class UsageTrackedTest {
|
||||
|
||||
@Test
|
||||
public void testUsedRecently() {
|
||||
TestUsageTracked usageTracked = new TestUsageTracked();
|
||||
assertTrue(usageTracked.usedInTheLast(1, TimeUnit.MINUTES));
|
||||
usageTracked.recordUsage();
|
||||
assertTrue(usageTracked.usedInTheLast(1, TimeUnit.MINUTES));
|
||||
|
||||
usageTracked.setLastUsed(System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1));
|
||||
assertFalse(usageTracked.usedInTheLast(1, TimeUnit.MINUTES));
|
||||
}
|
||||
|
||||
static final class TestUsageTracked extends UsageTracked {
|
||||
void setLastUsed(long lastUsed) {
|
||||
this.lastUsed = lastUsed;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.command.access;
|
||||
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.testcontainers.shaded.com.google.common.collect.ImmutableSet;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class CommandPermissionTest {
|
||||
|
||||
private static final ImmutableSet<CommandPermission> ALLOWED_READ_ONLY = ImmutableSet.of(
|
||||
CommandPermission.SYNC,
|
||||
CommandPermission.INFO,
|
||||
CommandPermission.EDITOR,
|
||||
CommandPermission.VERBOSE,
|
||||
CommandPermission.TREE,
|
||||
CommandPermission.SEARCH,
|
||||
CommandPermission.EXPORT,
|
||||
CommandPermission.RELOAD_CONFIG,
|
||||
CommandPermission.TRANSLATIONS,
|
||||
CommandPermission.LIST_GROUPS,
|
||||
CommandPermission.LIST_TRACKS,
|
||||
CommandPermission.USER_INFO,
|
||||
CommandPermission.USER_PERM_INFO,
|
||||
CommandPermission.USER_PERM_CHECK,
|
||||
CommandPermission.USER_PARENT_INFO,
|
||||
CommandPermission.USER_META_INFO,
|
||||
CommandPermission.USER_EDITOR,
|
||||
CommandPermission.USER_SHOW_TRACKS,
|
||||
CommandPermission.GROUP_INFO,
|
||||
CommandPermission.GROUP_PERM_INFO,
|
||||
CommandPermission.GROUP_PERM_CHECK,
|
||||
CommandPermission.GROUP_PARENT_INFO,
|
||||
CommandPermission.GROUP_META_INFO,
|
||||
CommandPermission.GROUP_EDITOR,
|
||||
CommandPermission.GROUP_LIST_MEMBERS,
|
||||
CommandPermission.GROUP_SHOW_TRACKS,
|
||||
CommandPermission.TRACK_INFO,
|
||||
CommandPermission.TRACK_EDITOR,
|
||||
CommandPermission.LOG_RECENT,
|
||||
CommandPermission.LOG_USER_HISTORY,
|
||||
CommandPermission.LOG_GROUP_HISTORY,
|
||||
CommandPermission.LOG_TRACK_HISTORY,
|
||||
CommandPermission.LOG_SEARCH,
|
||||
CommandPermission.LOG_NOTIFY,
|
||||
CommandPermission.SPONGE_PERMISSION_INFO,
|
||||
CommandPermission.SPONGE_PARENT_INFO,
|
||||
CommandPermission.SPONGE_OPTION_INFO
|
||||
);
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(CommandPermission.class)
|
||||
public void testReadOnly(CommandPermission permission) {
|
||||
String name = permission.name();
|
||||
assertEquals(ALLOWED_READ_ONLY.contains(permission), permission.isReadOnly(), name);
|
||||
}
|
||||
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.config;
|
||||
|
||||
import me.lucko.luckperms.common.config.generic.adapter.FileSecretConfigAdapter;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.logging.PluginLogger;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class FileSecretConfigAdapterTest {
|
||||
|
||||
@Mock private LuckPermsPlugin plugin;
|
||||
@Mock private PluginLogger logger;
|
||||
|
||||
@BeforeEach
|
||||
public void setupMocks() {
|
||||
lenient().when(this.plugin.getLogger()).thenReturn(this.logger);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead(@TempDir Path directory) throws IOException {
|
||||
Path path = directory.resolve("luckperms_server");
|
||||
Files.write(path, "test".getBytes());
|
||||
|
||||
FileSecretConfigAdapter adapter = new FileSecretConfigAdapter(this.plugin, directory.toString());
|
||||
|
||||
String server = adapter.getString("server", null);
|
||||
assertEquals("test", server);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoOp() throws IOException {
|
||||
FileSecretConfigAdapter adapter = new FileSecretConfigAdapter(this.plugin, null);
|
||||
|
||||
String server = adapter.getString("server", null);
|
||||
assertNull(server);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,21 +78,6 @@ public class FilterMongoTest {
|
||||
),
|
||||
// {"$or": [{"foo": "hello"}, {"bar": "world"}]}
|
||||
"{\"$or\": [{\"foo\": \"hello\"}, {\"bar\": \"world\"}]}"
|
||||
),
|
||||
Arguments.of(
|
||||
FilterList.or(
|
||||
TestField.FOO.isEqualTo("hello", ConstraintFactory.STRINGS),
|
||||
TestField.BAR.isNotEqualTo("world", ConstraintFactory.STRINGS),
|
||||
TestField.BAZ.isSimilarTo("abc%xyz", ConstraintFactory.STRINGS),
|
||||
TestField.BAZ.isNotSimilarTo("a_c", ConstraintFactory.STRINGS)
|
||||
),
|
||||
// {"$or": [
|
||||
// {"foo": "hello"},
|
||||
// {"bar": {"$ne": "world"}},
|
||||
// {"baz": {"$regularExpression": {"pattern": "abc.*xyz", "options": "i"}}},
|
||||
// {"baz": {"$not": {"$regularExpression": {"pattern": "a.c", "options": "i"}}}}
|
||||
// ]}
|
||||
"{\"$or\": [{\"foo\": \"hello\"}, {\"bar\": {\"$ne\": \"world\"}}, {\"baz\": {\"$regularExpression\": {\"pattern\": \"abc.*xyz\", \"options\": \"i\"}}}, {\"baz\": {\"$not\": {\"$regularExpression\": {\"pattern\": \"a.c\", \"options\": \"i\"}}}}]}"
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -109,7 +94,7 @@ public class FilterMongoTest {
|
||||
}
|
||||
|
||||
private enum TestField implements FilterField<Object, String> {
|
||||
FOO, BAR, BAZ;
|
||||
FOO, BAR;
|
||||
|
||||
@Override
|
||||
public String getValue(Object object) {
|
||||
|
||||
@@ -73,16 +73,6 @@ public class FilterSqlTest {
|
||||
),
|
||||
" WHERE foo = hello OR bar = world",
|
||||
" WHERE foo = ? OR bar = ?"
|
||||
),
|
||||
Arguments.of(
|
||||
FilterList.or(
|
||||
TestField.FOO.isEqualTo("hello", ConstraintFactory.STRINGS),
|
||||
TestField.BAR.isNotEqualTo("world", ConstraintFactory.STRINGS),
|
||||
TestField.BAZ.isSimilarTo("abc%xyz", ConstraintFactory.STRINGS),
|
||||
TestField.BAZ.isNotSimilarTo("a_c", ConstraintFactory.STRINGS)
|
||||
),
|
||||
" WHERE foo = hello OR bar != world OR baz LIKE abc%xyz OR baz NOT LIKE a_c",
|
||||
" WHERE foo = ? OR bar != ? OR baz LIKE ? OR baz NOT LIKE ?"
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -90,7 +80,7 @@ public class FilterSqlTest {
|
||||
@ParameterizedTest(name = "[{index}] {0}")
|
||||
@MethodSource
|
||||
public void testQueries(FilterList<Object> filters, String expectedSql, String expectedSqlParams) {
|
||||
FilterSqlBuilder<Object> sqlBuilder = new TestFilterSqlBuilder();
|
||||
TestFilterMongoBuilder sqlBuilder = new TestFilterMongoBuilder();
|
||||
sqlBuilder.visit(filters);
|
||||
|
||||
System.out.println(sqlBuilder.builder().toReadableString());
|
||||
@@ -101,7 +91,7 @@ public class FilterSqlTest {
|
||||
}
|
||||
|
||||
private enum TestField implements FilterField<Object, String> {
|
||||
FOO, BAR, BAZ;
|
||||
FOO, BAR;
|
||||
|
||||
@Override
|
||||
public String getValue(Object object) {
|
||||
@@ -114,7 +104,7 @@ public class FilterSqlTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestFilterSqlBuilder extends FilterSqlBuilder<Object> {
|
||||
private static final class TestFilterMongoBuilder extends FilterSqlBuilder<Object> {
|
||||
|
||||
@Override
|
||||
public void visitFieldName(FilterField<Object, ?> field) {
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.messaging;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import me.lucko.luckperms.common.actionlog.ActionJsonSerializer;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.messaging.message.ActionLogMessageImpl;
|
||||
import me.lucko.luckperms.common.messaging.message.CustomMessageImpl;
|
||||
import me.lucko.luckperms.common.messaging.message.UpdateMessageImpl;
|
||||
import me.lucko.luckperms.common.messaging.message.UserUpdateMessageImpl;
|
||||
import me.lucko.luckperms.common.util.gson.JObject;
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class MessageImplTest {
|
||||
|
||||
@Test
|
||||
public void testUpdateMessage() {
|
||||
UUID uuid = UUID.fromString("22f9e168-8815-44f1-83c8-b642ebfbcef2");
|
||||
|
||||
// encode
|
||||
UpdateMessageImpl msg = new UpdateMessageImpl(uuid);
|
||||
assertEquals("{\"id\":\"22f9e168-8815-44f1-83c8-b642ebfbcef2\",\"type\":\"update\"}", msg.asEncodedString());
|
||||
|
||||
// decode
|
||||
msg = UpdateMessageImpl.decode(new JsonObject(), uuid);
|
||||
assertEquals(uuid, msg.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserUpdateMessage() {
|
||||
UUID uuid = UUID.fromString("22f9e168-8815-44f1-83c8-b642ebfbcef2");
|
||||
UUID userUuid = UUID.fromString("4c087cd9-f444-4c52-8438-e03e57ba2e8e");
|
||||
|
||||
// encode
|
||||
UserUpdateMessageImpl msg = new UserUpdateMessageImpl(uuid, userUuid);
|
||||
// {"id":"22f9e168-8815-44f1-83c8-b642ebfbcef2","type":"userupdate","content":{"userUuid":"4c087cd9-f444-4c52-8438-e03e57ba2e8e"}}
|
||||
assertEquals("{\"id\":\"22f9e168-8815-44f1-83c8-b642ebfbcef2\",\"type\":\"userupdate\",\"content\":{\"userUuid\":\"4c087cd9-f444-4c52-8438-e03e57ba2e8e\"}}", msg.asEncodedString());
|
||||
|
||||
// decode
|
||||
msg = UserUpdateMessageImpl.decode(new JObject().add("userUuid", userUuid.toString()).toJson(), uuid);
|
||||
assertEquals(uuid, msg.getId());
|
||||
assertEquals(userUuid, msg.getUserUniqueId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionLogMessage() {
|
||||
UUID uuid = UUID.fromString("22f9e168-8815-44f1-83c8-b642ebfbcef2");
|
||||
LoggedAction action = LoggedAction.build()
|
||||
.source(UUID.fromString("d3500320-564c-436e-87a0-026d7f2c92f6"))
|
||||
.sourceName("Test")
|
||||
.targetType(Action.Target.Type.GROUP)
|
||||
.targetName("test")
|
||||
.description("test")
|
||||
.timestamp(Instant.ofEpochSecond(1))
|
||||
.build();
|
||||
|
||||
// encode
|
||||
ActionLogMessageImpl msg = new ActionLogMessageImpl(uuid, action);
|
||||
// {"id":"22f9e168-8815-44f1-83c8-b642ebfbcef2","type":"log","content":{"timestamp":1,"source":{"uniqueId":"d3500320-564c-436e-87a0-026d7f2c92f6","name":"Test"},"target":{"type":"GROUP","name":"test"},"description":"test"}}
|
||||
assertEquals("{\"id\":\"22f9e168-8815-44f1-83c8-b642ebfbcef2\",\"type\":\"log\",\"content\":{\"timestamp\":1,\"source\":{\"uniqueId\":\"d3500320-564c-436e-87a0-026d7f2c92f6\",\"name\":\"Test\"},\"target\":{\"type\":\"GROUP\",\"name\":\"test\"},\"description\":\"test\"}}", msg.asEncodedString());
|
||||
|
||||
// decode
|
||||
msg = ActionLogMessageImpl.decode(ActionJsonSerializer.serialize(action), uuid);
|
||||
assertEquals(uuid, msg.getId());
|
||||
assertEquals(action, msg.getAction());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomMessage() {
|
||||
UUID uuid = UUID.fromString("22f9e168-8815-44f1-83c8-b642ebfbcef2");
|
||||
String channelId = "test";
|
||||
String payload = "test";
|
||||
|
||||
// encode
|
||||
CustomMessageImpl msg = new CustomMessageImpl(uuid, channelId, payload);
|
||||
// {"id":"22f9e168-8815-44f1-83c8-b642ebfbcef2","type":"custom","content":{"channelId":"test","payload":"test"}}
|
||||
assertEquals("{\"id\":\"22f9e168-8815-44f1-83c8-b642ebfbcef2\",\"type\":\"custom\",\"content\":{\"channelId\":\"test\",\"payload\":\"test\"}}", msg.asEncodedString());
|
||||
|
||||
// decode
|
||||
msg = CustomMessageImpl.decode(new JObject().add("channelId", channelId).add("payload", payload).toJson(), uuid);
|
||||
assertEquals(uuid, msg.getId());
|
||||
assertEquals(channelId, msg.getChannelId());
|
||||
assertEquals(payload, msg.getPayload());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.node;
|
||||
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.node.factory.NodeCommandFactory;
|
||||
import me.lucko.luckperms.common.node.types.Inheritance;
|
||||
import me.lucko.luckperms.common.node.types.Meta;
|
||||
import me.lucko.luckperms.common.node.types.Permission;
|
||||
import me.lucko.luckperms.common.node.types.Prefix;
|
||||
import net.luckperms.api.node.Node;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class NodeCommandFactoryTest {
|
||||
|
||||
private static Stream<Arguments> testUndoCommand() {
|
||||
return Stream.of(
|
||||
Arguments.of("group test permission unset test", Permission.builder().permission("test").build(), HolderType.GROUP, false),
|
||||
Arguments.of("user test permission unset test", Permission.builder().permission("test").build(), HolderType.USER, false),
|
||||
Arguments.of("user test permission unsettemp test", Permission.builder().permission("test").expiry(1, TimeUnit.HOURS).build(), HolderType.USER, false),
|
||||
Arguments.of("user test permission unset test server=foo world=bar", Permission.builder().permission("test").withContext("server", "foo").withContext("world", "bar").build(), HolderType.USER, false),
|
||||
Arguments.of("user test permission unset test global", Permission.builder().permission("test").build(), HolderType.USER, true),
|
||||
Arguments.of("user test parent remove test", Inheritance.builder().group("test").build(), HolderType.USER, false),
|
||||
Arguments.of("user test parent removetemp test", Inheritance.builder().group("test").expiry(1, TimeUnit.HOURS).build(), HolderType.USER, false),
|
||||
Arguments.of("user test meta removeprefix 100 test", Prefix.builder().priority(100).prefix("test").build(), HolderType.USER, false),
|
||||
Arguments.of("user test meta removetempprefix 100 test", Prefix.builder().priority(100).prefix("test").expiry(1, TimeUnit.HOURS).build(), HolderType.USER, false),
|
||||
Arguments.of("user test meta removeprefix 100 \"hello world\"", Prefix.builder().priority(100).prefix("hello world").build(), HolderType.USER, false),
|
||||
Arguments.of("user test meta unset foo", Meta.builder().key("foo").value("bar").build(), HolderType.USER, false),
|
||||
Arguments.of("user test meta unsettemp foo", Meta.builder().key("foo").value("bar").expiry(1, TimeUnit.HOURS).build(), HolderType.USER, false)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "[{index}] {0}")
|
||||
@MethodSource
|
||||
public void testUndoCommand(String expected, Node node, HolderType holderType, boolean explicitGlobalContext) {
|
||||
String result = NodeCommandFactory.undoCommand(node, "test", holderType, explicitGlobalContext);
|
||||
assertEquals(expected, result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.node;
|
||||
|
||||
import me.lucko.luckperms.common.filter.Comparison;
|
||||
import me.lucko.luckperms.common.filter.Constraint;
|
||||
import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher;
|
||||
import me.lucko.luckperms.common.node.matcher.StandardNodeMatchers;
|
||||
import me.lucko.luckperms.common.node.types.Permission;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class NodeMatcherTest {
|
||||
|
||||
@Test
|
||||
public void testKey() {
|
||||
ConstraintNodeMatcher<Node> matcher = StandardNodeMatchers.key("foo");
|
||||
Constraint<String> constraint = matcher.getConstraint();
|
||||
|
||||
assertEquals(Comparison.EQUAL, constraint.comparison());
|
||||
assertEquals("foo", constraint.value());
|
||||
|
||||
ConstraintNodeMatcher<Permission> typedMatcher = StandardNodeMatchers.key(Permission.builder().permission("foo").build());
|
||||
Constraint<String> typedConstraint = typedMatcher.getConstraint();
|
||||
|
||||
assertEquals(Comparison.EQUAL, typedConstraint.comparison());
|
||||
assertEquals("foo", typedConstraint.value());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"foo, foo%",
|
||||
})
|
||||
public void testKeyStartsWith(String value, String expectedConstraint) {
|
||||
ConstraintNodeMatcher<Node> matcher = StandardNodeMatchers.keyStartsWith(value);
|
||||
Constraint<String> constraint = matcher.getConstraint();
|
||||
|
||||
assertEquals(Comparison.SIMILAR, constraint.comparison());
|
||||
assertEquals(expectedConstraint, constraint.value());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"foo, meta.foo.%",
|
||||
})
|
||||
public void testMetaKey(String value, String expectedConstraint) {
|
||||
ConstraintNodeMatcher<MetaNode> matcher = StandardNodeMatchers.metaKey(value);
|
||||
Constraint<String> constraint = matcher.getConstraint();
|
||||
|
||||
assertEquals(Comparison.SIMILAR, constraint.comparison());
|
||||
assertEquals(expectedConstraint, constraint.value());
|
||||
}
|
||||
|
||||
|
||||
private static Stream<Arguments> testType() {
|
||||
return Stream.of(
|
||||
Arguments.of(NodeType.REGEX_PERMISSION, "r=%"),
|
||||
Arguments.of(NodeType.INHERITANCE, "group.%"),
|
||||
Arguments.of(NodeType.PREFIX, "prefix.%.%"),
|
||||
Arguments.of(NodeType.SUFFIX, "suffix.%.%"),
|
||||
Arguments.of(NodeType.META, "meta.%.%"),
|
||||
Arguments.of(NodeType.WEIGHT, "weight.%"),
|
||||
Arguments.of(NodeType.DISPLAY_NAME, "displayname.%")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
public void testType(NodeType<?> type, String expectedValue) {
|
||||
ConstraintNodeMatcher<?> matcher = StandardNodeMatchers.type(type);
|
||||
Constraint<String> constraint = matcher.getConstraint();
|
||||
|
||||
assertEquals(Comparison.SIMILAR, constraint.comparison());
|
||||
assertEquals(expectedValue, constraint.value());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -139,9 +139,7 @@ public class NodeParseTest {
|
||||
"prefix.0.hello, 0, hello",
|
||||
"prefix.100.hello world, 100, hello world",
|
||||
"prefix.100.HELLO world &123, 100, HELLO world &123",
|
||||
"prefix.100., 100, ''",
|
||||
"prefix.100.hello\\.world, 100, hello.world",
|
||||
"prefix.100.hello.world, 100, hello.world",
|
||||
"prefix.100., 100, ''"
|
||||
})
|
||||
public void testPrefix(String key, int expectedPriority, String expectedValue) {
|
||||
Prefix.Builder builder = Prefix.parse(key);
|
||||
@@ -159,8 +157,7 @@ public class NodeParseTest {
|
||||
"prefix.",
|
||||
"prefix.hello",
|
||||
"prefix.100",
|
||||
"prefix.hello.hello",
|
||||
"suffix.100.hello"
|
||||
"prefix.hello.hello"
|
||||
})
|
||||
public void testPrefixFail(String key) {
|
||||
Prefix.Builder builder = Prefix.parse(key);
|
||||
@@ -174,9 +171,7 @@ public class NodeParseTest {
|
||||
"suffix.0.hello, 0, hello",
|
||||
"suffix.100.hello world, 100, hello world",
|
||||
"suffix.100.HELLO world &123, 100, HELLO world &123",
|
||||
"suffix.100., 100, ''",
|
||||
"suffix.100.hello\\.world, 100, hello.world",
|
||||
"suffix.100.hello.world, 100, hello.world",
|
||||
"suffix.100., 100, ''"
|
||||
})
|
||||
public void testSuffix(String key, int expectedPriority, String expectedValue) {
|
||||
Suffix.Builder builder = Suffix.parse(key);
|
||||
@@ -194,8 +189,7 @@ public class NodeParseTest {
|
||||
"suffix.",
|
||||
"suffix.hello",
|
||||
"suffix.100",
|
||||
"suffix.hello.hello",
|
||||
"prefix.100.hello"
|
||||
"suffix.hello.hello"
|
||||
})
|
||||
public void testSuffixFail(String key) {
|
||||
Suffix.Builder builder = Suffix.parse(key);
|
||||
@@ -206,10 +200,7 @@ public class NodeParseTest {
|
||||
@CsvSource({
|
||||
"meta.k.v, k, v",
|
||||
"meta.hello.world, hello, world",
|
||||
"meta.hello., hello, ''",
|
||||
"meta.a\\.b.hel\\.lo, a.b, hel.lo",
|
||||
"meta.a\\\\.b.hel\\.lo, a\\.b, hel.lo",
|
||||
"meta.a.b.c, a, b.c"
|
||||
"meta.hello., hello, ''"
|
||||
})
|
||||
public void testMeta(String key, String expectedKey, String expectedValue) {
|
||||
Meta.Builder builder = Meta.parse(key);
|
||||
|
||||
Loaded 100 of 206 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user