From 31d435dc2b49eceee747edc06f33f131d16632aa Mon Sep 17 00:00:00 2001
From: Luck
Date: Thu, 22 Feb 2018 22:09:37 +0000
Subject: [PATCH] Update web related functionality to point to new locations
and APIs (#770) (#784)
---
.../luckperms/bukkit/LPBukkitPlugin.java | 11 +-
.../luckperms/bungee/LPBungeePlugin.java | 11 +-
.../delegates/manager/ApiContextManager.java | 4 +-
.../impl/generic/other/HolderEditor.java | 8 +-
.../commands/impl/misc/CheckCommand.java | 2 +-
.../commands/impl/misc/DebugCommand.java | 110 ++-------
.../commands/impl/misc/EditorCommand.java | 8 +-
.../commands/impl/misc/TreeCommand.java | 41 +---
.../commands/impl/misc/VerboseCommand.java | 6 +-
.../common/commands/impl/user/UserInfo.java | 2 +-
.../luckperms/common/config/ConfigKeys.java | 14 +-
.../common/{inheritance => }/graph/Graph.java | 2 +-
.../graph/GraphTraversers.java | 2 +-
.../graph/TraversalAlgorithm.java | 2 +-
.../common/inheritance/InheritanceGraph.java | 6 +-
.../luckperms/common/locale/CommandSpec.java | 8 +-
.../common/plugin/LuckPermsPlugin.java | 5 +-
.../AllParentsByWeightHolder.java | 2 +-
.../primarygroup/ParentsByWeightHolder.java | 2 +-
.../common/treeview/ImmutableTreeNode.java | 14 ++
.../luckperms/common/treeview/TreeView.java | 201 +++++-----------
.../me/lucko/luckperms/common/utils/Gist.java | 189 ---------------
.../common/utils/StackTracePrinter.java | 110 +++++++++
.../gson/JArray.java} | 59 +++--
.../luckperms/common/utils/gson/JElement.java | 37 +++
.../luckperms/common/utils/gson/JObject.java | 74 ++++++
.../common/utils/{ => web}/HttpClient.java | 2 +-
.../luckperms/common/utils/web/Pastebin.java | 43 ++++
.../common/utils/web/StandardPastebin.java | 161 +++++++++++++
.../luckperms/common/verbose/CheckData.java | 36 +++
.../common/verbose/VerboseHandler.java | 6 +-
.../common/verbose/VerboseListener.java | 217 +++++-------------
.../luckperms/common/webeditor/WebEditor.java | 116 ++++------
.../luckperms/nukkit/LPNukkitPlugin.java | 11 +-
.../luckperms/sponge/LPSpongePlugin.java | 11 +-
35 files changed, 749 insertions(+), 784 deletions(-)
rename common/src/main/java/me/lucko/luckperms/common/{inheritance => }/graph/Graph.java (96%)
rename common/src/main/java/me/lucko/luckperms/common/{inheritance => }/graph/GraphTraversers.java (99%)
rename common/src/main/java/me/lucko/luckperms/common/{inheritance => }/graph/TraversalAlgorithm.java (97%)
delete mode 100644 common/src/main/java/me/lucko/luckperms/common/utils/Gist.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/utils/StackTracePrinter.java
rename common/src/main/java/me/lucko/luckperms/common/{treeview/TreeViewBuilder.java => utils/gson/JArray.java} (55%)
create mode 100644 common/src/main/java/me/lucko/luckperms/common/utils/gson/JElement.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/utils/gson/JObject.java
rename common/src/main/java/me/lucko/luckperms/common/utils/{ => web}/HttpClient.java (98%)
create mode 100644 common/src/main/java/me/lucko/luckperms/common/utils/web/Pastebin.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/utils/web/StandardPastebin.java
diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java
index 7690ce44..e1aeebcc 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java
@@ -105,8 +105,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Stream;
-import javax.annotation.Nullable;
-
/**
* LuckPerms implementation for the Bukkit API.
*/
@@ -190,7 +188,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
private void enable() {
this.startTime = System.currentTimeMillis();
sendStartupBanner(getConsoleSender());
- this.verboseHandler = new VerboseHandler(this.scheduler.asyncBukkit(), getVersion());
+ this.verboseHandler = new VerboseHandler(this.scheduler.asyncBukkit());
this.permissionVault = new PermissionVault(this.scheduler.asyncBukkit());
this.logDispatcher = new LogDispatcher(this);
@@ -539,14 +537,13 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
}
- @Nullable
@Override
- public Contexts getContextForUser(User user) {
+ public Optional getContextForUser(User user) {
Player player = getPlayer(user);
if (player == null) {
- return null;
+ return Optional.empty();
}
- return this.contextManager.getApplicableContexts(player);
+ return Optional.of(this.contextManager.getApplicableContexts(player));
}
@Override
diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java
index 3ebc9e28..9e5610cf 100644
--- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java
+++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java
@@ -90,8 +90,6 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
-import javax.annotation.Nullable;
-
/**
* LuckPerms implementation for the BungeeCord API.
*/
@@ -141,7 +139,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
public void onEnable() {
this.startTime = System.currentTimeMillis();
sendStartupBanner(getConsoleSender());
- this.verboseHandler = new VerboseHandler(this.scheduler.async(), getVersion());
+ this.verboseHandler = new VerboseHandler(this.scheduler.async());
this.permissionVault = new PermissionVault(this.scheduler.async());
this.logDispatcher = new LogDispatcher(this);
@@ -339,14 +337,13 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return Optional.empty();
}
- @Nullable
@Override
- public Contexts getContextForUser(User user) {
+ public Optional getContextForUser(User user) {
ProxiedPlayer player = getPlayer(user);
if (player == null) {
- return null;
+ return Optional.empty();
}
- return this.contextManager.getApplicableContexts(player);
+ return Optional.of(this.contextManager.getApplicableContexts(player));
}
@Override
diff --git a/common/src/main/java/me/lucko/luckperms/common/api/delegates/manager/ApiContextManager.java b/common/src/main/java/me/lucko/luckperms/common/api/delegates/manager/ApiContextManager.java
index ed434fb3..59f7b7bd 100644
--- a/common/src/main/java/me/lucko/luckperms/common/api/delegates/manager/ApiContextManager.java
+++ b/common/src/main/java/me/lucko/luckperms/common/api/delegates/manager/ApiContextManager.java
@@ -74,14 +74,14 @@ public class ApiContextManager implements me.lucko.luckperms.api.context.Context
@Override
public Optional lookupApplicableContext(@Nonnull User user) {
Objects.requireNonNull(user, "user");
- return Optional.ofNullable(this.plugin.getContextForUser(ApiUser.cast(user))).map(c -> c.getContexts().makeImmutable());
+ return this.plugin.getContextForUser(ApiUser.cast(user)).map(c -> c.getContexts().makeImmutable());
}
@Nonnull
@Override
public Optional lookupApplicableContexts(@Nonnull User user) {
Objects.requireNonNull(user, "user");
- return Optional.ofNullable(this.plugin.getContextForUser(ApiUser.cast(user)));
+ return this.plugin.getContextForUser(ApiUser.cast(user));
}
@Nonnull
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/other/HolderEditor.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/other/HolderEditor.java
index acb660ab..7b66ee43 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/other/HolderEditor.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/other/HolderEditor.java
@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.impl.generic.other;
-import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import me.lucko.luckperms.common.commands.ArgumentPermissions;
@@ -40,6 +39,7 @@ import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
+import me.lucko.luckperms.common.utils.web.StandardPastebin;
import me.lucko.luckperms.common.webeditor.WebEditor;
import net.kyori.text.Component;
@@ -69,14 +69,14 @@ public class HolderEditor extends SubCommand {
JsonObject payload = WebEditor.formPayload(Collections.singletonList(holder), sender, label, plugin);
// upload the payload data to gist
- String gistId = WebEditor.postToGist(new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create().toJson(payload));
- if (gistId == null) {
+ String pasteId = StandardPastebin.BYTEBIN.postJson(payload).id();
+ if (pasteId == null) {
Message.EDITOR_UPLOAD_FAILURE.send(sender);
return CommandResult.STATE_ERROR;
}
// form a url for the editor
- String url = plugin.getConfiguration().get(ConfigKeys.WEB_EDITOR_URL_PATTERN) + "?" + gistId;
+ String url = plugin.getConfiguration().get(ConfigKeys.WEB_EDITOR_URL_PATTERN) + "?" + pasteId;
Message.EDITOR_URL.send(sender);
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/CheckCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/CheckCommand.java
index f0df5929..64a05ed9 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/CheckCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/CheckCommand.java
@@ -68,7 +68,7 @@ public class CheckCommand extends SingleCommand {
return CommandResult.STATE_ERROR;
}
- Tristate tristate = user.getCachedData().getPermissionData(plugin.getContextForUser(user)).getPermissionValue(permission, CheckOrigin.INTERNAL);
+ Tristate tristate = user.getCachedData().getPermissionData(plugin.getContextForUser(user).orElse(plugin.getContextManager().getStaticContexts())).getPermissionValue(permission, CheckOrigin.INTERNAL);
Message.CHECK_RESULT.send(sender, user.getFriendlyName(), permission, CommandUtils.formatTristate(tristate));
return CommandResult.SUCCESS;
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/DebugCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/DebugCommand.java
index 687d737f..75e886b2 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/DebugCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/DebugCommand.java
@@ -27,9 +27,6 @@ package me.lucko.luckperms.common.commands.impl.misc;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.caching.MetaContexts;
@@ -51,9 +48,11 @@ import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.processors.PermissionProcessor;
-import me.lucko.luckperms.common.utils.Gist;
import me.lucko.luckperms.common.utils.Predicates;
-import me.lucko.luckperms.common.utils.TextUtils;
+import me.lucko.luckperms.common.utils.gson.JArray;
+import me.lucko.luckperms.common.utils.gson.JObject;
+import me.lucko.luckperms.common.utils.web.Pastebin;
+import me.lucko.luckperms.common.utils.web.StandardPastebin;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
@@ -66,7 +65,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
-import java.util.function.Supplier;
+import java.util.function.BiConsumer;
import java.util.stream.Collectors;
public class DebugCommand extends SingleCommand {
@@ -80,19 +79,26 @@ public class DebugCommand extends SingleCommand {
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, List args, String label) {
Message.DEBUG_START.send(sender);
- Gist gist = Gist.builder()
- .description("LuckPerms Debug Output")
- .file("__DEBUG__.md", TextUtils.joinNewline("# Debug Output", "The debugging data can be found in the files below."))
- .file("platform.json", GSON.toJson(getPlatformData(plugin).toJson()))
- .file("storage.json", GSON.toJson(getStorageData(plugin).toJson()))
- .file("context.json", GSON.toJson(getContextData(plugin).toJson()))
- .file("players.json", GSON.toJson(getPlayersData(plugin).toJson()))
- .upload();
+ StringBuilder sb = new StringBuilder();
+ sb.append("LuckPerms Debug Output\n\n\n");
+
+ BiConsumer builder = (name, content) -> {
+ sb.append("-- ").append(name).append(" --\n");
+ sb.append(GSON.toJson(content.toJson()));
+ sb.append("\n\n");
+ };
+
+ builder.accept("platform.json", getPlatformData(plugin));
+ builder.accept("storage.json", getStorageData(plugin));
+ builder.accept("context.json", getContextData(plugin));
+ builder.accept("players.json", getPlayersData(plugin));
+
+ Pastebin.Paste paste = StandardPastebin.HASTEBIN.postPlain(sb.toString());
Message.DEBUG_URL.send(sender);
- Component message = TextComponent.builder(gist.getUrl()).color(TextColor.AQUA)
- .clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, String.valueOf(gist.getUrl())))
+ Component message = TextComponent.builder(paste.url()).color(TextColor.AQUA)
+ .clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, String.valueOf(paste.url())))
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the debugging data.").color(TextColor.GRAY)))
.build();
@@ -190,7 +196,7 @@ public class DebugCommand extends SingleCommand {
)
.add("activeContext", () -> {
JObject obj = new JObject();
- Contexts contexts = plugin.getContextForUser(user);
+ Contexts contexts = plugin.getContextForUser(user).orElse(null);
if (contexts != null) {
MetaContexts metaContexts = plugin.getContextManager().formMetaContexts(contexts);
obj.add("data", new JObject()
@@ -298,74 +304,4 @@ public class DebugCommand extends SingleCommand {
});
}
- // stupidly simply fluent gson wrappers
-
- private interface JElement {
- JsonElement toJson();
- }
-
- private static final class JObject implements JElement {
- private final JsonObject o = new JsonObject();
-
- @Override
- public JsonElement toJson() {
- return this.o;
- }
-
- public JObject add(String key, String value) {
- this.o.addProperty(key, value);
- return this;
- }
-
- public JObject add(String key, Number value) {
- this.o.addProperty(key, value);
- return this;
- }
-
- public JObject add(String key, Boolean value) {
- this.o.addProperty(key, value);
- return this;
- }
-
- public JObject add(String key, JsonElement value) {
- this.o.add(key, value);
- return this;
- }
-
- public JObject add(String key, JElement value) {
- return add(key, value.toJson());
- }
-
- public JObject add(String key, Supplier extends JElement> value) {
- return add(key, value.get().toJson());
- }
- }
-
- private static final class JArray implements JElement {
- private final JsonArray o = new JsonArray();
-
- @Override
- public JsonElement toJson() {
- return this.o;
- }
-
- public JArray add(String value) {
- this.o.add(value);
- return this;
- }
-
- public JArray add(JsonElement value) {
- this.o.add(value);
- return this;
- }
-
- public JArray add(JElement value) {
- return add(value.toJson());
- }
-
- public JArray add(Supplier extends JElement> value) {
- return add(value.get().toJson());
- }
- }
-
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/EditorCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/EditorCommand.java
index 3cade9a3..51f74544 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/EditorCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/EditorCommand.java
@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.impl.misc;
-import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import me.lucko.luckperms.common.commands.ArgumentPermissions;
@@ -41,6 +40,7 @@ import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
+import me.lucko.luckperms.common.utils.web.StandardPastebin;
import me.lucko.luckperms.common.webeditor.WebEditor;
import net.kyori.text.Component;
@@ -95,14 +95,14 @@ public class EditorCommand extends SingleCommand {
JsonObject payload = WebEditor.formPayload(holders, sender, label, plugin);
// upload the payload data to gist
- String gistId = WebEditor.postToGist(new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create().toJson(payload));
- if (gistId == null) {
+ String pasteId = StandardPastebin.BYTEBIN.postJson(payload).id();
+ if (pasteId == null) {
Message.EDITOR_UPLOAD_FAILURE.send(sender);
return CommandResult.STATE_ERROR;
}
// form a url for the editor
- String url = plugin.getConfiguration().get(ConfigKeys.WEB_EDITOR_URL_PATTERN) + "?" + gistId;
+ String url = plugin.getConfiguration().get(ConfigKeys.WEB_EDITOR_URL_PATTERN) + "?" + pasteId;
Message.EDITOR_URL.send(sender);
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/TreeCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/TreeCommand.java
index 77ee13aa..0085b87f 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/TreeCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/TreeCommand.java
@@ -30,14 +30,13 @@ import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SingleCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
-import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
+import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.treeview.TreeView;
-import me.lucko.luckperms.common.treeview.TreeViewBuilder;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.Uuids;
@@ -58,21 +57,17 @@ public class TreeCommand extends SingleCommand {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, List args, String label) {
String selection = ".";
- int maxLevel = 5;
String player = null;
if (!args.isEmpty()) {
selection = args.get(0);
}
if (args.size() > 1) {
- maxLevel = ArgumentUtils.handleIntOrElse(1, args, 5);
- }
- if (args.size() > 2) {
- player = args.get(2);
+ player = args.get(1);
}
+ User user;
if (player != null) {
- User user;
UUID u = Uuids.parseNullable(player);
if (u != null) {
user = plugin.getUserManager().getIfLoaded(u);
@@ -84,38 +79,20 @@ public class TreeCommand extends SingleCommand {
Message.USER_NOT_ONLINE.send(sender, player);
return CommandResult.STATE_ERROR;
}
-
- PermissionCache permissionData = user.getCachedData().getPermissionData(plugin.getContextForUser(user));
- TreeView view = TreeViewBuilder.newBuilder().rootPosition(selection).maxLevels(maxLevel).build(plugin.getPermissionVault());
-
- if (!view.hasData()) {
- Message.TREE_EMPTY.send(sender);
- return CommandResult.FAILURE;
- }
-
- Message.TREE_UPLOAD_START.send(sender);
- String url = view.uploadPasteData(plugin.getVersion(), user.getFriendlyName(), permissionData);
-
- Message.TREE_URL.send(sender);
-
- Component message = TextComponent.builder(url).color(TextColor.AQUA)
- .clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, String.valueOf(url)))
- .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the tree view.").color(TextColor.GRAY)))
- .build();
-
- sender.sendMessage(message);
- return CommandResult.SUCCESS;
+ } else {
+ user = null;
}
- TreeView view = TreeViewBuilder.newBuilder().rootPosition(selection).maxLevels(maxLevel).build(plugin.getPermissionVault());
-
+ TreeView view = new TreeView(plugin.getPermissionVault(), selection);
if (!view.hasData()) {
Message.TREE_EMPTY.send(sender);
return CommandResult.FAILURE;
}
Message.TREE_UPLOAD_START.send(sender);
- String url = view.uploadPasteData(plugin.getVersion());
+ PermissionCache permissionData = user == null ? null : user.getCachedData().getPermissionData(plugin.getContextForUser(user).orElse(plugin.getContextManager().getStaticContexts()));
+ String id = view.uploadPasteData(sender, user, permissionData);
+ String url = plugin.getConfiguration().get(ConfigKeys.TREE_VIEWER_URL_PATTERN) + "?" + id;
Message.TREE_URL.send(sender);
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/VerboseCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/VerboseCommand.java
index d3bf68b9..d0fa0b81 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/VerboseCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/VerboseCommand.java
@@ -31,6 +31,7 @@ import me.lucko.luckperms.common.commands.CommandPermission;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SingleCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
+import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message;
@@ -64,8 +65,6 @@ public class VerboseCommand extends SingleCommand {
return CommandResult.INVALID_ARGS;
}
- boolean noTraces = args.remove("--notrace") || args.remove("--notraces") || args.remove("--slim") || args.remove("-s");
- boolean attachRaw = args.remove("--raw");
String mode = args.get(0).toLowerCase();
if (mode.equals("on") || mode.equals("true") || mode.equals("record")) {
@@ -114,7 +113,8 @@ public class VerboseCommand extends SingleCommand {
Message.VERBOSE_OFF.send(sender);
} else {
Message.VERBOSE_UPLOAD_START.send(sender);
- String url = listener.uploadPasteData(!noTraces, attachRaw);
+ String id = listener.uploadPasteData();
+ String url = plugin.getConfiguration().get(ConfigKeys.VERBOSE_VIEWER_URL_PATTERN) + "?" + id;
Message.VERBOSE_RESULTS_URL.send(sender);
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserInfo.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserInfo.java
index 2ced264e..e08b9f80 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserInfo.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserInfo.java
@@ -100,7 +100,7 @@ public class UserInfo extends SubCommand {
String prefix = "&bNone";
String suffix = "&bNone";
String meta = "&bNone";
- Contexts contexts = plugin.getContextForUser(user);
+ Contexts contexts = plugin.getContextForUser(user).orElse(null);
if (contexts != null) {
ContextSet contextSet = contexts.getContexts();
if (!contextSet.isEmpty()) {
diff --git a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java
index b6bc56fe..91c65816 100644
--- a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java
+++ b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java
@@ -37,7 +37,7 @@ import me.lucko.luckperms.common.config.keys.IntegerKey;
import me.lucko.luckperms.common.config.keys.LowercaseStringKey;
import me.lucko.luckperms.common.config.keys.MapKey;
import me.lucko.luckperms.common.config.keys.StringKey;
-import me.lucko.luckperms.common.inheritance.graph.TraversalAlgorithm;
+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.TemporaryModifier;
@@ -476,7 +476,17 @@ public class ConfigKeys {
/**
* The URL of the web editor
*/
- public static final ConfigKey WEB_EDITOR_URL_PATTERN = StringKey.of("web-editor-url", "https://lpedit.lucko.me/");
+ public static final ConfigKey WEB_EDITOR_URL_PATTERN = StringKey.of("web-editor-url", "https://luckperms.github.io/editor/");
+
+ /**
+ * The URL of the verbose viewer
+ */
+ public static final ConfigKey VERBOSE_VIEWER_URL_PATTERN = StringKey.of("verbose-viewer-url", "https://luckperms.github.io/verbose/");
+
+ /**
+ * The URL of the tree viewer
+ */
+ public static final ConfigKey TREE_VIEWER_URL_PATTERN = StringKey.of("tree-viewer-url", "https://luckperms.github.io/treeview/");
private static Map> KEYS = null;
diff --git a/common/src/main/java/me/lucko/luckperms/common/inheritance/graph/Graph.java b/common/src/main/java/me/lucko/luckperms/common/graph/Graph.java
similarity index 96%
rename from common/src/main/java/me/lucko/luckperms/common/inheritance/graph/Graph.java
rename to common/src/main/java/me/lucko/luckperms/common/graph/Graph.java
index b223d0ad..b3477d43 100644
--- a/common/src/main/java/me/lucko/luckperms/common/inheritance/graph/Graph.java
+++ b/common/src/main/java/me/lucko/luckperms/common/graph/Graph.java
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
-package me.lucko.luckperms.common.inheritance.graph;
+package me.lucko.luckperms.common.graph;
/**
* A minimal functional interface for graph-structured data.
diff --git a/common/src/main/java/me/lucko/luckperms/common/inheritance/graph/GraphTraversers.java b/common/src/main/java/me/lucko/luckperms/common/graph/GraphTraversers.java
similarity index 99%
rename from common/src/main/java/me/lucko/luckperms/common/inheritance/graph/GraphTraversers.java
rename to common/src/main/java/me/lucko/luckperms/common/graph/GraphTraversers.java
index 1453333e..3d4aa5e6 100644
--- a/common/src/main/java/me/lucko/luckperms/common/inheritance/graph/GraphTraversers.java
+++ b/common/src/main/java/me/lucko/luckperms/common/graph/GraphTraversers.java
@@ -39,7 +39,7 @@
* limitations under the License.
*/
-package me.lucko.luckperms.common.inheritance.graph;
+package me.lucko.luckperms.common.graph;
import com.google.common.collect.AbstractIterator;
diff --git a/common/src/main/java/me/lucko/luckperms/common/inheritance/graph/TraversalAlgorithm.java b/common/src/main/java/me/lucko/luckperms/common/graph/TraversalAlgorithm.java
similarity index 97%
rename from common/src/main/java/me/lucko/luckperms/common/inheritance/graph/TraversalAlgorithm.java
rename to common/src/main/java/me/lucko/luckperms/common/graph/TraversalAlgorithm.java
index cd058f25..b1534218 100644
--- a/common/src/main/java/me/lucko/luckperms/common/inheritance/graph/TraversalAlgorithm.java
+++ b/common/src/main/java/me/lucko/luckperms/common/graph/TraversalAlgorithm.java
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
-package me.lucko.luckperms.common.inheritance.graph;
+package me.lucko.luckperms.common.graph;
public enum TraversalAlgorithm {
diff --git a/common/src/main/java/me/lucko/luckperms/common/inheritance/InheritanceGraph.java b/common/src/main/java/me/lucko/luckperms/common/inheritance/InheritanceGraph.java
index 9c96d5dc..dc9b0279 100644
--- a/common/src/main/java/me/lucko/luckperms/common/inheritance/InheritanceGraph.java
+++ b/common/src/main/java/me/lucko/luckperms/common/inheritance/InheritanceGraph.java
@@ -27,9 +27,9 @@ package me.lucko.luckperms.common.inheritance;
import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
-import me.lucko.luckperms.common.inheritance.graph.Graph;
-import me.lucko.luckperms.common.inheritance.graph.GraphTraversers;
-import me.lucko.luckperms.common.inheritance.graph.TraversalAlgorithm;
+import me.lucko.luckperms.common.graph.Graph;
+import me.lucko.luckperms.common.graph.GraphTraversers;
+import me.lucko.luckperms.common.graph.TraversalAlgorithm;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
diff --git a/common/src/main/java/me/lucko/luckperms/common/locale/CommandSpec.java b/common/src/main/java/me/lucko/luckperms/common/locale/CommandSpec.java
index ba2bd461..07bfc8dd 100644
--- a/common/src/main/java/me/lucko/luckperms/common/locale/CommandSpec.java
+++ b/common/src/main/java/me/lucko/luckperms/common/locale/CommandSpec.java
@@ -58,14 +58,12 @@ public enum CommandSpec {
VERBOSE("Manage verbose permission checking", "/%s verbose [filter]",
Arg.list(
Arg.create("on|record|off|paste", true, "whether to enable/disable logging, or to paste the logged output"),
- Arg.create("filter", false, "the filter to match entries against"),
- Arg.create("--slim", false, "add \"--slim\" to exclude trace data from the pasted output")
+ Arg.create("filter", false, "the filter to match entries against")
)
),
- TREE("Generate a tree view of permissions", "/%s tree [selection] [max level] [player]",
+ TREE("Generate a tree view of permissions", "/%s tree [scope] [player]",
Arg.list(
- Arg.create("selection", false, "the root of the tree. specify \".\" to include all permissions"),
- Arg.create("max level", false, "how many branch levels should be returned"),
+ Arg.create("scope", false, "the root of the tree. specify \".\" to include all permissions"),
Arg.create("player", false, "the name of an online player to check against")
)
),
diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java
index 258f8ecf..96adb28b 100644
--- a/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java
+++ b/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java
@@ -63,8 +63,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.stream.Stream;
-import javax.annotation.Nullable;
-
/**
* Main internal interface for LuckPerms plugins, providing the base for
* abstraction throughout the project.
@@ -332,8 +330,7 @@ public interface LuckPermsPlugin {
* @param user the user instance
* @return a contexts object, or null if one couldn't be generated
*/
- @Nullable
- Contexts getContextForUser(User user);
+ Optional getContextForUser(User user);
/**
* Gets the number of users online on the platform
diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java
index 49a25254..27e09c25 100644
--- a/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java
+++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java
@@ -43,7 +43,7 @@ public class AllParentsByWeightHolder extends CachedPrimaryGroupHolder {
@Override
protected String calculateValue() {
- Contexts contexts = this.user.getPlugin().getContextForUser(this.user);
+ Contexts contexts = this.user.getPlugin().getContextForUser(this.user).orElse(null);
if (contexts == null) {
contexts = this.user.getPlugin().getContextManager().getStaticContexts();
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java
index b5941252..87b009db 100644
--- a/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java
+++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java
@@ -40,7 +40,7 @@ public class ParentsByWeightHolder extends CachedPrimaryGroupHolder {
@Override
protected String calculateValue() {
- Contexts contexts = this.user.getPlugin().getContextForUser(this.user);
+ Contexts contexts = this.user.getPlugin().getContextForUser(this.user).orElse(null);
if (contexts == null) {
contexts = this.user.getPlugin().getContextManager().getStaticContexts();
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/treeview/ImmutableTreeNode.java b/common/src/main/java/me/lucko/luckperms/common/treeview/ImmutableTreeNode.java
index e5aad8ff..ffe69600 100644
--- a/common/src/main/java/me/lucko/luckperms/common/treeview/ImmutableTreeNode.java
+++ b/common/src/main/java/me/lucko/luckperms/common/treeview/ImmutableTreeNode.java
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.treeview;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
+import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.Collections;
@@ -101,6 +102,19 @@ public class ImmutableTreeNode implements Comparable {
return results;
}
+ public JsonObject toJson(String prefix) {
+ if (this.children == null) {
+ return new JsonObject();
+ }
+
+ JsonObject object = new JsonObject();
+ for (Map.Entry entry : this.children.entrySet()) {
+ String name = prefix + entry.getKey();
+ object.add(name, entry.getValue().toJson(name + "."));
+ }
+ return object;
+ }
+
@Override
public int compareTo(@Nonnull ImmutableTreeNode o) {
return (this.children != null) == o.getChildren().isPresent() ? 0 : (this.children != null ? 1 : -1);
diff --git a/common/src/main/java/me/lucko/luckperms/common/treeview/TreeView.java b/common/src/main/java/me/lucko/luckperms/common/treeview/TreeView.java
index f3f28480..412d67b0 100644
--- a/common/src/main/java/me/lucko/luckperms/common/treeview/TreeView.java
+++ b/common/src/main/java/me/lucko/luckperms/common/treeview/TreeView.java
@@ -26,22 +26,19 @@
package me.lucko.luckperms.common.treeview;
import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
+import com.google.gson.JsonObject;
-import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.caching.type.PermissionCache;
-import me.lucko.luckperms.common.utils.Gist;
-import me.lucko.luckperms.common.verbose.CheckOrigin;
+import me.lucko.luckperms.common.commands.sender.Sender;
+import me.lucko.luckperms.common.model.User;
+import me.lucko.luckperms.common.utils.gson.JObject;
+import me.lucko.luckperms.common.utils.web.StandardPastebin;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
/**
* A readable view of a branch of {@link TreeNode}s.
@@ -52,15 +49,16 @@ public class TreeView {
// the root of the tree
private final String rootPosition;
- // how many levels / branches to display
- private final int maxLevel;
-
// the actual tree object
private final ImmutableTreeNode view;
- public TreeView(PermissionVault source, String rootPosition, int maxLevel) {
+ public TreeView(PermissionVault source, String rootPosition) {
+ if (rootPosition.equals("") || rootPosition.equals("*")) {
+ rootPosition = ".";
+ } else if (!rootPosition.equals(".") && rootPosition.endsWith(".")) {
+ rootPosition = rootPosition.substring(0, rootPosition.length() - 1);
+ }
this.rootPosition = rootPosition;
- this.maxLevel = maxLevel;
Optional root = findRoot(rootPosition, source);
this.view = root.map(TreeNode::makeImmutableCopy).orElse(null);
@@ -115,152 +113,61 @@ public class TreeView {
}
/**
- * Converts the view to a readable list
+ * Uploads the data contained in this TreeView and returns the id.
*
- * The list contains KV pairs, where the key is the tree padding/structure,
- * and the value is the actual permission.
- *
- * @return a list of the nodes in this view
+ * @param sender the sender
+ * @param user the reference user, or null
+ * @param checker the permission data instance to check against, or null
+ * @return the id, or null
*/
- private List> asTreeList() {
+ public String uploadPasteData(Sender sender, User user, PermissionCache checker) {
+ // only paste if there is actually data here
+ if (!hasData()) {
+ throw new IllegalStateException();
+ }
+
// work out the prefix to apply
// since the view is relative, we need to prepend this to all permissions
String prefix = this.rootPosition.equals(".") ? "" : (this.rootPosition + ".");
+ JsonObject jsonTree = this.view.toJson(prefix);
+ JObject metadata = new JObject()
+ .add("time", DATE_FORMAT.format(new Date(System.currentTimeMillis())))
+ .add("root", this.rootPosition)
+ .add("uploader", new JObject()
+ .add("name", sender.getNameWithLocation())
+ .add("uuid", sender.getUuid().toString())
+ );
- List> ret = new ArrayList<>();
+ JObject checks;
+ if (user != null && checker != null) {
+ metadata.add("referenceUser", new JObject()
+ .add("name", user.getFriendlyName())
+ .add("uuid", user.getUuid().toString())
+ );
- // iterate the node endings in the view
- for (Map.Entry s : this.view.getNodeEndings()) {
- // don't include the node if it exceeds the max level
- if (s.getKey() >= this.maxLevel) {
- continue;
+ checks = new JObject();
+ for (Map.Entry node : this.view.getNodeEndings()) {
+ String permission = prefix + node.getValue();
+ checks.add(permission, checker.getPermissionValue(permission).name().toLowerCase());
}
-
- // generate the tree padding characters from the node level
- String treeStructure = Strings.repeat("│ ", s.getKey()) + "├── ";
- // generate the permission, using the prefix and the node
- String permission = prefix + s.getValue();
-
- ret.add(Maps.immutableEntry(treeStructure, permission));
+ } else {
+ checks = null;
}
- return ret;
- }
+ JsonObject payload = new JObject()
+ .add("metadata", metadata)
+ .add("data", new JObject()
+ .add("tree", jsonTree)
+ .consume(obj -> {
+ if (checks != null) {
+ obj.add("checkResults", checks);
+ }
+ })
+ )
+ .toJson();
- /**
- * Uploads the data contained in this TreeView to a paste, and returns the URL.
- *
- * @param version the plugin version string
- * @return the url, or null
- */
- public String uploadPasteData(String version) {
- // only paste if there is actually data here
- if (!hasData()) {
- throw new IllegalStateException();
- }
-
- // get the data contained in the view in a list form
- // for each entry, the key is the padding tree characters
- // and the value is the actual permission string
- List> ret = asTreeList();
-
- // build the header of the paste
- ImmutableList.Builder builder = getPasteHeader(version, "none", ret.size());
-
- // add the tree data
- builder.add("```");
- for (Map.Entry e : ret) {
- builder.add(e.getKey() + e.getValue());
- }
- builder.add("```");
-
- // clear the initial data map
- ret.clear();
-
- // upload the return the data
- Gist gist = Gist.builder()
- .description("LuckPerms Permission Tree")
- .file("luckperms-tree.md", builder.build().stream().collect(Collectors.joining("\n")))
- .upload();
-
- return gist.getUrl();
- }
-
- /**
- * Uploads the data contained in this TreeView to a paste, and returns the URL.
- *
- * Unlike {@link #uploadPasteData(String)}, this method will check each permission
- * against a corresponding user, and colorize the output depending on the check results.
- *
- * @param version the plugin version string
- * @param username the username of the reference user
- * @param checker the permission data instance to check against
- * @return the url, or null
- */
- public String uploadPasteData(String version, String username, PermissionCache checker) {
- // only paste if there is actually data here
- if (!hasData()) {
- throw new IllegalStateException();
- }
-
- // get the data contained in the view in a list form
- // for each entry, the key is the padding tree characters
- // and the value is the actual permission string
- List> ret = asTreeList();
-
- // build the header of the paste
- ImmutableList.Builder builder = getPasteHeader(version, username, ret.size());
-
- // add the tree data
- builder.add("```diff");
- for (Map.Entry e : ret) {
-
- // lookup a permission value for the node
- Tristate tristate = checker.getPermissionValue(e.getValue(), CheckOrigin.INTERNAL);
-
- // append the data to the paste
- builder.add(getTristateDiffPrefix(tristate) + e.getKey() + e.getValue());
- }
- builder.add("```");
-
- // clear the initial data map
- ret.clear();
-
- // upload the return the data
- Gist gist = Gist.builder()
- .description("LuckPerms Permission Tree")
- .file("luckperms-tree.md", builder.build().stream().collect(Collectors.joining("\n")))
- .upload();
-
- return gist.getUrl();
- }
-
- private static String getTristateDiffPrefix(Tristate t) {
- switch (t) {
- case TRUE:
- return "+ ";
- case FALSE:
- return "- ";
- default:
- return "# ";
- }
- }
-
- private ImmutableList.Builder getPasteHeader(String version, String referenceUser, int size) {
- String date = DATE_FORMAT.format(new Date(System.currentTimeMillis()));
- String selection = this.rootPosition.equals(".") ? "any" : "`" + this.rootPosition + "`";
-
- return ImmutableList.builder()
- .add("## Permission Tree")
- .add("#### This file was automatically generated by [LuckPerms](https://github.com/lucko/LuckPerms) v" + version)
- .add("")
- .add("### Metadata")
- .add("| Selection | Max Recursion | Reference User | Size | Produced at |")
- .add("|-----------|---------------|----------------|------|-------------|")
- .add("| " + selection + " | " + this.maxLevel + " | " + referenceUser + " | **" + size + "** | " + date + " |")
- .add("")
- .add("### Output");
+ return StandardPastebin.BYTEBIN.postJson(payload).id();
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/Gist.java b/common/src/main/java/me/lucko/luckperms/common/utils/Gist.java
deleted file mode 100644
index fe65777e..00000000
--- a/common/src/main/java/me/lucko/luckperms/common/utils/Gist.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * This file is part of LuckPerms, licensed under the MIT License.
- *
- * Copyright (c) lucko (Luck)
- * 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.utils;
-
-import com.google.common.collect.ImmutableList;
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import com.google.gson.stream.JsonWriter;
-
-import okhttp3.FormBody;
-import okhttp3.MediaType;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import okhttp3.ResponseBody;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Represents a posted GitHub Gist
- */
-public class Gist {
- private static final Gson GSON = new Gson();
-
- private static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");
-
- private static final String GIST_API_URL = "https://api.github.com/gists";
- private static final String GIT_IO_URL = "https://git.io";
-
- public static Builder builder() {
- return new Builder();
- }
-
- private final String url;
- private final String id;
-
- private Gist(String url, String id) {
- this.url = url;
- this.id = id;
- }
-
- public String getUrl() {
- return this.url;
- }
-
- public String getId() {
- return this.id;
- }
-
- private static final class GistFile {
- private final String name;
- private final String content;
-
- private GistFile(String name, String content) {
- this.name = name;
- this.content = content;
- }
- }
-
- public static final class Builder {
- private final List files = new ArrayList<>();
- private boolean shorten = true;
- private String description = "LuckPerms Gist";
-
- private Builder() {
-
- }
-
- public Builder file(String name, String content) {
- this.files.add(new GistFile(name, content));
- return this;
- }
-
- public Builder shorten(boolean shorten) {
- this.shorten = shorten;
- return this;
- }
-
- public Builder description(String description) {
- this.description = description;
- return this;
- }
-
- public Gist upload() {
- return Gist.upload(ImmutableList.copyOf(this.files), this.shorten, this.description);
- }
- }
-
- private static Gist upload(List files, boolean shorten, String description) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (JsonWriter jw = new JsonWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8))) {
- jw.beginObject();
- jw.name("description").value(description);
- jw.name("public").value(false);
- jw.name("files").beginObject();
- for (GistFile file : files) {
- jw.name(file.name).beginObject().name("content").value(file.content).endObject();
- }
- jw.endObject().endObject();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- RequestBody body = RequestBody.create(JSON_TYPE, out.toByteArray());
- Request request = new Request.Builder()
- .url(GIST_API_URL)
- .post(body)
- .build();
-
- try (Response response = HttpClient.makeCall(request)) {
- try (ResponseBody responseBody = response.body()) {
- if (responseBody == null) {
- throw new RuntimeException("No response");
- }
-
- String id;
- String pasteUrl;
- try (InputStream inputStream = responseBody.byteStream()) {
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
- JsonObject object = GSON.fromJson(reader, JsonObject.class);
- id = object.get("id").getAsString();
- pasteUrl = object.get("html_url").getAsString();
- }
- }
-
- if (shorten) {
- pasteUrl = shortenUrl(pasteUrl);
- }
-
- return new Gist(pasteUrl, id);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static String shortenUrl(String pasteUrl) {
- RequestBody requestBody = new FormBody.Builder()
- .add("url", pasteUrl)
- .build();
-
- Request request = new Request.Builder()
- .url(GIT_IO_URL)
- .post(requestBody)
- .build();
-
- try (Response response = HttpClient.makeCall(request)) {
- String location = response.header("Location");
- if (location == null) {
- throw new RuntimeException("No location header");
- }
- return location;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return pasteUrl;
- }
-}
diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/StackTracePrinter.java b/common/src/main/java/me/lucko/luckperms/common/utils/StackTracePrinter.java
new file mode 100644
index 00000000..f8492f40
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/utils/StackTracePrinter.java
@@ -0,0 +1,110 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * 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.utils;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+public final class StackTracePrinter {
+ public static Consumer elementToString(Consumer consumer) {
+ return e -> consumer.accept(e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : ""));
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private final int truncateLength;
+ private final Predicate shouldPrintPredicate;
+
+ private StackTracePrinter(int truncateLength, Predicate shouldPrintPredicate) {
+ this.truncateLength = truncateLength;
+ this.shouldPrintPredicate = shouldPrintPredicate;
+ }
+
+ public int process(StackTraceElement[] stackTrace, Consumer consumer) {
+ // how many lines have been printed
+ int count = 0;
+ // if we're printing elements yet
+ boolean printing = false;
+
+ for (StackTraceElement e : stackTrace) {
+ // start printing when the predicate passes
+ if (!printing && this.shouldPrintPredicate.test(e)) {
+ printing = true;
+ }
+
+ if (!printing) continue;
+ if (count >= this.truncateLength) break;
+
+ consumer.accept(e);
+ count++;
+ }
+ if (stackTrace.length > this.truncateLength) {
+ return stackTrace.length - this.truncateLength;
+ }
+ return 0;
+ }
+
+ public Builder toBuilder() {
+ Builder builder = new Builder();
+ builder.truncateLength = this.truncateLength;
+ builder.shouldPrintPredicate = this.shouldPrintPredicate;
+ return builder;
+ }
+
+ public static final class Builder {
+ private int truncateLength = Integer.MAX_VALUE;
+ private Predicate shouldPrintPredicate = Predicates.alwaysTrue();
+
+ private Builder() {
+
+ }
+
+ public Builder truncateLength(int truncateLength) {
+ this.truncateLength = truncateLength;
+ return this;
+ }
+
+ public Builder ignoreElementsMatching(Predicate super StackTraceElement> predicate) {
+ this.shouldPrintPredicate = this.shouldPrintPredicate.and(predicate.negate());
+ return this;
+ }
+
+ public Builder ignoreClass(String className) {
+ return ignoreElementsMatching(e -> e.getClassName().equals(className));
+ }
+
+ public Builder ignoreClassStartingWith(String className) {
+ return ignoreElementsMatching(e -> e.getClassName().startsWith(className));
+ }
+
+ public StackTracePrinter build() {
+ return new StackTracePrinter(this.truncateLength, this.shouldPrintPredicate);
+ }
+ }
+
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/treeview/TreeViewBuilder.java b/common/src/main/java/me/lucko/luckperms/common/utils/gson/JArray.java
similarity index 55%
rename from common/src/main/java/me/lucko/luckperms/common/treeview/TreeViewBuilder.java
rename to common/src/main/java/me/lucko/luckperms/common/utils/gson/JArray.java
index d42bb5eb..663298a1 100644
--- a/common/src/main/java/me/lucko/luckperms/common/treeview/TreeViewBuilder.java
+++ b/common/src/main/java/me/lucko/luckperms/common/utils/gson/JArray.java
@@ -23,45 +23,42 @@
* SOFTWARE.
*/
-package me.lucko.luckperms.common.treeview;
+package me.lucko.luckperms.common.utils.gson;
-/**
- * Builds a {@link TreeView}.
- */
-public class TreeViewBuilder {
- public static TreeViewBuilder newBuilder() {
- return new TreeViewBuilder();
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class JArray implements JElement {
+ private final JsonArray array = new JsonArray();
+
+ @Override
+ public JsonArray toJson() {
+ return this.array;
}
- private String rootPosition;
- private int maxLevels;
-
- private TreeViewBuilder() {
- this.rootPosition = ".";
- this.maxLevels = 5;
- }
-
- public TreeViewBuilder rootPosition(String rootPosition) {
- this.rootPosition = rootPosition;
+ public JArray add(String value) {
+ this.array.add(value);
return this;
}
- public TreeViewBuilder maxLevels(int maxLevels) {
- this.maxLevels = maxLevels;
+ public JArray add(JsonElement value) {
+ this.array.add(value);
return this;
}
- public TreeView build(PermissionVault source) {
- if (this.maxLevels < 1) {
- this.maxLevels = 1;
- }
- if (this.rootPosition.equals("") || this.rootPosition.equals("*")) {
- this.rootPosition = ".";
- } else if (!this.rootPosition.equals(".") && this.rootPosition.endsWith(".")) {
- this.rootPosition = this.rootPosition.substring(0, this.rootPosition.length() - 1);
- }
-
- return new TreeView(source, this.rootPosition, this.maxLevels);
+ public JArray add(JElement value) {
+ return add(value.toJson());
}
-}
+ public JArray add(Supplier extends JElement> value) {
+ return add(value.get().toJson());
+ }
+
+ public JArray consume(Consumer super JArray> consumer) {
+ consumer.accept(this);
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/gson/JElement.java b/common/src/main/java/me/lucko/luckperms/common/utils/gson/JElement.java
new file mode 100644
index 00000000..7056c3b9
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/utils/gson/JElement.java
@@ -0,0 +1,37 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * 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.utils.gson;
+
+import com.google.gson.JsonElement;
+
+/**
+ * Stupidly simple fluent gson wrappers
+ */
+public interface JElement {
+
+ JsonElement toJson();
+
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/gson/JObject.java b/common/src/main/java/me/lucko/luckperms/common/utils/gson/JObject.java
new file mode 100644
index 00000000..61977dba
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/utils/gson/JObject.java
@@ -0,0 +1,74 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * 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.utils.gson;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class JObject implements JElement {
+ private final JsonObject object = new JsonObject();
+
+ @Override
+ public JsonObject toJson() {
+ return this.object;
+ }
+
+ public JObject add(String key, String value) {
+ this.object.addProperty(key, value);
+ return this;
+ }
+
+ public JObject add(String key, Number value) {
+ this.object.addProperty(key, value);
+ return this;
+ }
+
+ public JObject add(String key, Boolean value) {
+ this.object.addProperty(key, value);
+ return this;
+ }
+
+ public JObject add(String key, JsonElement value) {
+ this.object.add(key, value);
+ return this;
+ }
+
+ public JObject add(String key, JElement value) {
+ return add(key, value.toJson());
+ }
+
+ public JObject add(String key, Supplier extends JElement> value) {
+ return add(key, value.get().toJson());
+ }
+
+ public JObject consume(Consumer super JObject> consumer) {
+ consumer.accept(this);
+ return this;
+ }
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/HttpClient.java b/common/src/main/java/me/lucko/luckperms/common/utils/web/HttpClient.java
similarity index 98%
rename from common/src/main/java/me/lucko/luckperms/common/utils/HttpClient.java
rename to common/src/main/java/me/lucko/luckperms/common/utils/web/HttpClient.java
index 2c069974..a2ebbf29 100644
--- a/common/src/main/java/me/lucko/luckperms/common/utils/HttpClient.java
+++ b/common/src/main/java/me/lucko/luckperms/common/utils/web/HttpClient.java
@@ -23,7 +23,7 @@
* SOFTWARE.
*/
-package me.lucko.luckperms.common.utils;
+package me.lucko.luckperms.common.utils.web;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/web/Pastebin.java b/common/src/main/java/me/lucko/luckperms/common/utils/web/Pastebin.java
new file mode 100644
index 00000000..a7f99de3
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/utils/web/Pastebin.java
@@ -0,0 +1,43 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * 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.utils.web;
+
+import com.google.gson.JsonElement;
+
+public interface Pastebin {
+
+ Paste postJson(JsonElement element);
+
+ Paste postPlain(String content);
+
+ String getRawUrl(String id);
+
+ interface Paste {
+ String url();
+ String id();
+ }
+
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/web/StandardPastebin.java b/common/src/main/java/me/lucko/luckperms/common/utils/web/StandardPastebin.java
new file mode 100644
index 00000000..5d11d999
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/utils/web/StandardPastebin.java
@@ -0,0 +1,161 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * 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.utils.web;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+
+public enum StandardPastebin implements Pastebin {
+
+ BYTEBIN {
+ public static final String URL = "https://bytebin.lucko.me/";
+ private static final String POST_URL = URL + "post";
+
+ @Override
+ public String getPostUrl() {
+ return POST_URL;
+ }
+
+ @Override
+ protected String parseIdFromResult(BufferedReader reader) {
+ JsonObject object = GSON.fromJson(reader, JsonObject.class);
+ return object.get("key").getAsString();
+ }
+
+ @Override
+ public String getRawUrl(String id) {
+ return URL + id;
+ }
+ },
+
+ HASTEBIN {
+ private static final String URL = "https://hastebin.com/";
+ private static final String RAW_URL = URL + "raw/";
+ private static final String POST_URL = URL + "documents";
+
+ @Override
+ public String getPostUrl() {
+ return POST_URL;
+ }
+
+ @Override
+ protected String parseIdFromResult(BufferedReader reader) {
+ JsonObject object = GSON.fromJson(reader, JsonObject.class);
+ return object.get("key").getAsString();
+ }
+
+ @Override
+ public String getRawUrl(String id) {
+ return RAW_URL + id;
+ }
+ };
+
+ private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
+ private static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");
+ private static final MediaType PLAIN_TYPE = MediaType.parse("text/plain; charset=utf-8");
+
+ protected abstract String getPostUrl();
+ protected abstract String parseIdFromResult(BufferedReader reader);
+
+ @Override
+ public Pastebin.Paste postJson(JsonElement content) {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(bytes))) {
+ GSON.toJson(content, writer);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ return post(RequestBody.create(JSON_TYPE, bytes.toByteArray()));
+ }
+
+ @Override
+ public Pastebin.Paste postPlain(String content) {
+ return post(RequestBody.create(PLAIN_TYPE, content));
+ }
+
+ private Pastebin.Paste post(RequestBody body) {
+ Request request = new Request.Builder()
+ .url(getPostUrl())
+ .post(body)
+ .build();
+
+ try (Response response = HttpClient.makeCall(request)) {
+ try (ResponseBody responseBody = response.body()) {
+ if (responseBody == null) {
+ throw new RuntimeException("No response");
+ }
+
+ try (InputStream inputStream = responseBody.byteStream()) {
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
+ String id = parseIdFromResult(reader);
+ String url = getRawUrl(id);
+ return new Paste(url, id);
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static final class Paste implements Pastebin.Paste {
+ private final String url;
+ private final String id;
+
+ private Paste(String url, String id) {
+ this.url = url;
+ this.id = id;
+ }
+
+ @Override
+ public String url() {
+ return this.url;
+ }
+
+ @Override
+ public String id() {
+ return this.id;
+ }
+ }
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/verbose/CheckData.java b/common/src/main/java/me/lucko/luckperms/common/verbose/CheckData.java
index 093a31e9..dec98c7b 100644
--- a/common/src/main/java/me/lucko/luckperms/common/verbose/CheckData.java
+++ b/common/src/main/java/me/lucko/luckperms/common/verbose/CheckData.java
@@ -25,8 +25,15 @@
package me.lucko.luckperms.common.verbose;
+import com.google.gson.JsonObject;
+
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.context.ImmutableContextSet;
+import me.lucko.luckperms.common.utils.StackTracePrinter;
+import me.lucko.luckperms.common.utils.gson.JArray;
+import me.lucko.luckperms.common.utils.gson.JObject;
+
+import java.util.Map;
/**
* Holds the data from a permission check
@@ -95,4 +102,33 @@ public class CheckData {
public Tristate getResult() {
return this.result;
}
+
+ private JObject formBaseJson() {
+ return new JObject()
+ .add("who", new JObject()
+ .add("identifier", this.checkTarget)
+ )
+ .add("permission", this.permission)
+ .add("result", this.result.name().toLowerCase())
+ .add("origin", this.checkOrigin.name().toLowerCase())
+ .add("context", new JArray()
+ .consume(arr -> {
+ for (Map.Entry contextPair : this.checkContext.toSet()) {
+ arr.add(new JObject().add("key", contextPair.getKey()).add("value", contextPair.getValue()));
+ }
+ })
+ );
+ }
+
+ public JsonObject toJson() {
+ return formBaseJson().toJson();
+ }
+
+ public JsonObject toJson(StackTracePrinter tracePrinter) {
+ return formBaseJson()
+ .add("trace", new JArray()
+ .consume(arr -> tracePrinter.process(this.checkTrace, StackTracePrinter.elementToString(arr::add)))
+ )
+ .toJson();
+ }
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseHandler.java b/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseHandler.java
index 1de2cbab..06b0ce02 100644
--- a/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseHandler.java
+++ b/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseHandler.java
@@ -40,7 +40,6 @@ import java.util.concurrent.Executor;
* Accepts {@link CheckData} and passes it onto registered {@link VerboseListener}s.
*/
public class VerboseHandler implements Runnable {
- private final String pluginVersion;
// the listeners currently registered
private final Map listeners;
@@ -54,8 +53,7 @@ public class VerboseHandler implements Runnable {
// if the handler should shutdown
private boolean shutdown = false;
- public VerboseHandler(Executor executor, String pluginVersion) {
- this.pluginVersion = "v" + pluginVersion;
+ public VerboseHandler(Executor executor) {
this.listeners = new ConcurrentHashMap<>();
this.queue = new ConcurrentLinkedQueue<>();
@@ -95,7 +93,7 @@ public class VerboseHandler implements Runnable {
* @param notify if the sender should be notified in chat on each check
*/
public void registerListener(Sender sender, VerboseFilter filter, boolean notify) {
- this.listeners.put(sender.getUuid(), new VerboseListener(this.pluginVersion, sender, filter, notify));
+ this.listeners.put(sender.getUuid(), new VerboseListener(sender, filter, notify));
this.listening = true;
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseListener.java b/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseListener.java
index 32a244e6..75146fa8 100644
--- a/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseListener.java
+++ b/common/src/main/java/me/lucko/luckperms/common/verbose/VerboseListener.java
@@ -25,7 +25,7 @@
package me.lucko.luckperms.common.verbose;
-import com.google.common.collect.ImmutableList;
+import com.google.gson.JsonObject;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.common.commands.CommandManager;
@@ -33,8 +33,11 @@ import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.CommandUtils;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.utils.DateUtil;
-import me.lucko.luckperms.common.utils.Gist;
+import me.lucko.luckperms.common.utils.StackTracePrinter;
import me.lucko.luckperms.common.utils.TextUtils;
+import me.lucko.luckperms.common.utils.gson.JArray;
+import me.lucko.luckperms.common.utils.gson.JObject;
+import me.lucko.luckperms.common.utils.web.StandardPastebin;
import net.kyori.text.TextComponent;
import net.kyori.text.event.HoverEvent;
@@ -45,7 +48,6 @@ import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
/**
* Accepts and processes {@link CheckData}, passed from the {@link VerboseHandler}.
@@ -55,17 +57,36 @@ public class VerboseListener {
// how much data should we store before stopping.
private static final int DATA_TRUNCATION = 10000;
- // how many traces should we add
- private static final int TRACE_DATA_TRUNCATION = 250;
// how many lines should we include in each stack trace send as a chat message
private static final int STACK_TRUNCATION_CHAT = 15;
// how many lines should we include in each stack trace in the web output
private static final int STACK_TRUNCATION_WEB = 30;
+ private static final StackTracePrinter FILTERING_PRINTER = StackTracePrinter.builder()
+ .ignoreClassStartingWith("me.lucko.luckperms.")
+ .ignoreClassStartingWith("com.github.benmanes.caffeine")
+ .ignoreClass("java.util.concurrent.CompletableFuture")
+ .ignoreClass("java.util.concurrent.ConcurrentHashMap")
+ .build();
+
+ private static final StackTracePrinter CHAT_FILTERED_PRINTER = FILTERING_PRINTER.toBuilder()
+ .truncateLength(STACK_TRUNCATION_CHAT)
+ .build();
+
+ private static final StackTracePrinter CHAT_UNFILTERED_PRINTER = StackTracePrinter.builder()
+ .truncateLength(STACK_TRUNCATION_CHAT)
+ .build();
+
+ private static final StackTracePrinter WEB_FILTERED_PRINTER = FILTERING_PRINTER.toBuilder()
+ .truncateLength(STACK_TRUNCATION_WEB)
+ .build();
+
+ private static final StackTracePrinter WEB_UNFILTERED_PRINTER = StackTracePrinter.builder()
+ .truncateLength(STACK_TRUNCATION_WEB)
+ .build();
+
// the time when the listener was first registered
private final long startTime = System.currentTimeMillis();
- // the version of the plugin. (used when we paste data to gist)
- private final String pluginVersion;
// the sender to notify each time the listener processes a check which passes the filter
private final Sender notifiedSender;
// the filter
@@ -80,8 +101,7 @@ public class VerboseListener {
// the checks which passed the filter, up to a max size of #DATA_TRUNCATION
private final List results = new ArrayList<>(DATA_TRUNCATION / 10);
- public VerboseListener(String pluginVersion, Sender notifiedSender, VerboseFilter filter, boolean notify) {
- this.pluginVersion = pluginVersion;
+ public VerboseListener(Sender notifiedSender, VerboseFilter filter, boolean notify) {
this.notifiedSender = notifiedSender;
this.filter = filter;
this.notify = notify;
@@ -132,7 +152,13 @@ public class VerboseListener {
hover.add("&bContext: &r" + CommandUtils.contextSetToString(data.getCheckContext()));
hover.add("&bTrace: &r");
- int overflow = readStack(data, STACK_TRUNCATION_CHAT, e -> hover.add("&7" + e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : "")));
+ Consumer printer = StackTracePrinter.elementToString(str -> hover.add("&7" + str));
+ int overflow;
+ if (data.getCheckOrigin() == CheckOrigin.API || data.getCheckOrigin() == CheckOrigin.INTERNAL) {
+ overflow = CHAT_UNFILTERED_PRINTER.process(data.getCheckTrace(), printer);
+ } else {
+ overflow = CHAT_FILTERED_PRINTER.process(data.getCheckTrace(), printer);
+ }
if (overflow != 0) {
hover.add("&f... and " + overflow + " more");
}
@@ -146,11 +172,9 @@ public class VerboseListener {
/**
* Uploads the captured data in this listener to a paste and returns the url
*
- * @param showTraces if stack traces should be included in the output
- * @param attachRaw if the rawdata should be attached to the gist
* @return the url
*/
- public String uploadPasteData(boolean showTraces, boolean attachRaw) {
+ public String uploadPasteData() {
// retrieve variables
long now = System.currentTimeMillis();
@@ -163,148 +187,42 @@ public class VerboseListener {
if (this.filter.isBlank()){
filter = "any";
} else {
- filter = "`" + this.filter.toString() + "`";
+ filter = this.filter.toString();
}
- // start building the message output
- ImmutableList.Builder prettyOutput = ImmutableList.builder()
- .add("## Verbose Checking Output")
- .add("#### This file was automatically generated by [LuckPerms](https://github.com/lucko/LuckPerms) " + this.pluginVersion)
- .add("")
- .add("### Metadata")
- .add("| Key | Value |")
- .add("|-----|-------|")
- .add("| Start Time | " + startDate + " |")
- .add("| End Time | " + endDate + " |")
- .add("| Duration | " + duration +" |")
- .add("| Count | **" + this.matchedCounter.get() + "** / " + this.counter.get() + " |")
- .add("| User | " + this.notifiedSender.getNameWithLocation() + " |")
- .add("| Filter | " + filter + " |")
- .add("| Include traces | " + showTraces + " |")
- .add("");
+ boolean truncated = this.matchedCounter.get() > this.results.size();
- // warn if data was truncated
- if (this.matchedCounter.get() > this.results.size()) {
- prettyOutput.add("**WARN:** Result set exceeded max size of " + DATA_TRUNCATION + ". The output below was truncated to " + DATA_TRUNCATION + " entries.");
- prettyOutput.add("");
- }
-
- // explain why some traces may be missing
- if (showTraces && this.results.size() > TRACE_DATA_TRUNCATION) {
- prettyOutput.add("**WARN:** Result set exceeded size of " + TRACE_DATA_TRUNCATION + ". The traced output below was truncated to " + TRACE_DATA_TRUNCATION + " entries. ");
- prettyOutput.add("Either refine the query using a more specific filter, or disable tracing by adding '--slim' to the end of the paste command.");
- prettyOutput.add("");
- }
-
- // print the format of the output
- prettyOutput.add("### Output")
- .add("Format: `` `` ``")
- .add("")
- .add("___")
- .add("");
-
- // build the csv output - will only be appended to if this is enabled.
- ImmutableList.Builder csvOutput = ImmutableList.builder()
- .add("User,Permission,Result");
-
- // how many instances have been printed so far
- AtomicInteger printedCount = new AtomicInteger(0);
+ JObject metadata = new JObject()
+ .add("startTime", startDate)
+ .add("endTime", endDate)
+ .add("duration", duration)
+ .add("count", new JObject()
+ .add("matched", this.matchedCounter.get())
+ .add("total", this.counter.get())
+ )
+ .add("uploader", new JObject()
+ .add("name", this.notifiedSender.getNameWithLocation())
+ .add("uuid", this.notifiedSender.getUuid().toString())
+ )
+ .add("filter", filter)
+ .add("truncated", truncated);
+ JArray data = new JArray();
for (CheckData c : this.results) {
- if (!showTraces) {
-
- // if traces aren't being shown, just append using raw markdown
- prettyOutput.add("`" + c.getCheckTarget() + "` - " + c.getPermission() + " - " + getTristateSymbol(c.getResult()) + " ");
-
- } else if (printedCount.incrementAndGet() > TRACE_DATA_TRUNCATION) {
-
- // if we've gone over the trace truncation, just append the raw info.
- // we still have to use html, as the rest of this section is still using it.
- prettyOutput.add("
" + c.getCheckTarget() + "
- " + c.getPermission() + " - " + getTristateSymbol(c.getResult()));
-
+ if (c.getCheckOrigin() == CheckOrigin.API || c.getCheckOrigin() == CheckOrigin.INTERNAL) {
+ data.add(c.toJson(WEB_UNFILTERED_PRINTER));
} else {
-
- // append the full output.
- prettyOutput.add("" + c.getCheckTarget() + "
- " + c.getPermission() + " - " + getTristateSymbol(c.getResult()) + "
");
-
- // append the spoiler text
- prettyOutput.add("
Origin: " + c.getCheckOrigin().name() + "
");
- prettyOutput.add("
Context: " + CommandUtils.stripColor(CommandUtils.contextSetToString(c.getCheckContext())) + "
");
- prettyOutput.add("
Trace:
");
-
- int overflow = readStack(c, STACK_TRUNCATION_WEB, e -> prettyOutput.add(e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : "")));
- if (overflow != 0) {
- prettyOutput.add("... and " + overflow + " more");
- }
-
- prettyOutput.add("
");
- }
-
- // if we're including a raw csv output, append that too
- if (attachRaw) {
- csvOutput.add(escapeCommas(c.getCheckTarget()) + "," + escapeCommas(c.getPermission()) + "," + c.getResult().name().toLowerCase());
+ data.add(c.toJson(WEB_FILTERED_PRINTER));
}
}
this.results.clear();
- Gist.Builder gist = Gist.builder()
- .description("LuckPerms Verbose Checking Output")
- .file("luckperms-verbose.md", prettyOutput.build().stream().collect(Collectors.joining("\n")));
+ JsonObject payload = new JObject()
+ .add("metadata", metadata)
+ .add("data", data)
+ .toJson();
- if (attachRaw) {
- gist.file("raw-data.csv", csvOutput.build().stream().collect(Collectors.joining("\n")));
- }
-
- return gist.upload().getUrl();
- }
-
- /**
- * Reads a stack trace from a {@link CheckData} instance.
- *
- * @param data the data to read from
- * @param truncateLength the length when we should stop reading the stack
- * @param consumer the element consumer
- * @return how many elements were left unread, or 0 if everything was read
- */
- private static int readStack(CheckData data, int truncateLength, Consumer consumer) {
- StackTraceElement[] stack = data.getCheckTrace();
-
- // how many lines have been printed
- int count = 0;
- // if we're printing elements yet
- boolean printing = false;
-
- for (StackTraceElement e : stack) {
- // start printing when we escape LP internals code
- boolean shouldStartPrinting = !printing && (
- (data.getCheckOrigin() == CheckOrigin.API || data.getCheckOrigin() == CheckOrigin.INTERNAL) || (
- !e.getClassName().startsWith("me.lucko.luckperms.") &&
- // all used within the checking impl somewhere
- !e.getClassName().equals("java.util.concurrent.CompletableFuture") &&
- !e.getClassName().startsWith("com.github.benmanes.caffeine") &&
- !e.getClassName().equals("java.util.concurrent.ConcurrentHashMap")
- )
- );
-
- if (shouldStartPrinting) {
- printing = true;
- }
-
- if (!printing) continue;
- if (count >= truncateLength) break;
-
- consumer.accept(e);
- count++;
- }
-
- if (stack.length > truncateLength) {
- return stack.length - truncateLength;
- }
- return 0;
- }
-
- private static String escapeCommas(String s) {
- return s.contains(",") ? "\"" + s + "\"" : s;
+ return StandardPastebin.BYTEBIN.postJson(payload).id();
}
private static String getTristateColor(Tristate tristate) {
@@ -318,17 +236,6 @@ public class VerboseListener {
}
}
- private static String getTristateSymbol(Tristate tristate) {
- switch (tristate) {
- case TRUE:
- return "✔️";
- case FALSE:
- return "❌";
- default:
- return "❔";
- }
- }
-
public Sender getNotifiedSender() {
return this.notifiedSender;
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/webeditor/WebEditor.java b/common/src/main/java/me/lucko/luckperms/common/webeditor/WebEditor.java
index f45a7435..e01220ce 100644
--- a/common/src/main/java/me/lucko/luckperms/common/webeditor/WebEditor.java
+++ b/common/src/main/java/me/lucko/luckperms/common/webeditor/WebEditor.java
@@ -30,7 +30,6 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.common.commands.sender.Sender;
@@ -41,9 +40,11 @@ import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeModel;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
-import me.lucko.luckperms.common.utils.Gist;
-import me.lucko.luckperms.common.utils.HttpClient;
import me.lucko.luckperms.common.utils.Uuids;
+import me.lucko.luckperms.common.utils.gson.JArray;
+import me.lucko.luckperms.common.utils.gson.JObject;
+import me.lucko.luckperms.common.utils.web.HttpClient;
+import me.lucko.luckperms.common.utils.web.StandardPastebin;
import okhttp3.Request;
import okhttp3.Response;
@@ -66,54 +67,49 @@ import java.util.stream.Stream;
public final class WebEditor {
private static final Gson GSON = new Gson();
- private static final String FILE_NAME = "luckperms-data.json";
- private static final String GIST_API_URL = "https://api.github.com/gists";
-
private static final String USER_ID_PATTERN = "user/";
private static final String GROUP_ID_PATTERN = "group/";
- private static void writeData(PermissionHolder holder, JsonObject payload) {
- payload.addProperty("who", getHolderIdentifier(holder));
- payload.addProperty("whoFriendly", holder.getFriendlyName());
- if (holder.getType().isUser()) {
- payload.addProperty("whoUuid", ((User) holder).getUuid().toString());
- }
-
- // attach the holders permissions
- payload.add("nodes", serializePermissions(holder.getEnduringNodes().values().stream().map(NodeModel::fromNode)));
+ private static JObject writeData(PermissionHolder holder) {
+ return new JObject()
+ .add("who", new JObject()
+ .add("id", getHolderIdentifier(holder))
+ .add("friendly", holder.getFriendlyName())
+ .consume(obj -> {
+ if (holder.getType().isUser()) {
+ obj.add("uuid", ((User) holder).getUuid().toString());
+ }
+ }))
+ .add("nodes", serializePermissions(holder.getEnduringNodes().values().stream().map(NodeModel::fromNode)));
}
public static JsonObject formPayload(List holders, Sender sender, String cmdLabel, LuckPermsPlugin plugin) {
Preconditions.checkArgument(!holders.isEmpty(), "holders is empty");
// form the payload data
- JsonObject payload = new JsonObject();
-
- payload.addProperty("cmdAlias", cmdLabel);
- payload.addProperty("uploadedBy", sender.getNameWithLocation());
- payload.addProperty("uploadedByUuid", sender.getUuid().toString());
- payload.addProperty("time", System.currentTimeMillis());
-
- if (holders.size() == 1) {
- writeData(holders.get(0), payload);
- } else {
- JsonArray tabs = new JsonArray();
- for (PermissionHolder holder : holders) {
- JsonObject o = new JsonObject();
- writeData(holder, o);
- tabs.add(o);
- }
- payload.add("tabs", tabs);
- }
-
- // attach an array of all permissions known to the server, to use for tab completion in the editor
- JsonArray knownPermsArray = new JsonArray();
- for (String perm : plugin.getPermissionVault().rootAsList()) {
- knownPermsArray.add(new JsonPrimitive(perm));
- }
- payload.add("knownPermissions", knownPermsArray);
-
- return payload;
+ return new JObject()
+ .add("metadata", new JObject()
+ .add("cmdAlias", cmdLabel)
+ .add("uploader", new JObject()
+ .add("name", sender.getNameWithLocation())
+ .add("uuid", sender.getUuid().toString())
+ )
+ .add("time", System.currentTimeMillis())
+ )
+ .add("sessions", new JArray()
+ .consume(arr -> {
+ for (PermissionHolder holder : holders) {
+ arr.add(writeData(holder));
+ }
+ })
+ )
+ .add("knownPermissions", new JArray()
+ .consume(arr -> {
+ for (String perm : plugin.getPermissionVault().rootAsList()) {
+ arr.add(perm);
+ }
+ })
+ ).toJson();
}
private static String getHolderIdentifier(PermissionHolder holder) {
@@ -152,19 +148,9 @@ public final class WebEditor {
}
}
- public static String postToGist(String content) {
- Gist gist = Gist.builder()
- .description("LuckPerms Web Editor Data")
- .shorten(false)
- .file(FILE_NAME, content)
- .upload();
-
- return gist.getId();
- }
-
public static JsonObject getDataFromGist(String id) {
Request request = new Request.Builder()
- .url(GIST_API_URL + "/" + id)
+ .url(StandardPastebin.BYTEBIN.getRawUrl(id))
.build();
try (Response response = HttpClient.makeCall(request)) {
@@ -175,29 +161,7 @@ public final class WebEditor {
try (InputStream inputStream = responseBody.byteStream()) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
- JsonObject object = new Gson().fromJson(reader, JsonObject.class);
- JsonObject files = object.get("files").getAsJsonObject();
- JsonObject permsFile = files.get(FILE_NAME).getAsJsonObject();
-
- // uh..
- if (permsFile.get("truncated").getAsBoolean()) {
- try (Response rawResponse = HttpClient.makeCall(new Request.Builder().url(permsFile.get("raw_url").getAsString()).build())) {
- try (ResponseBody rawResponseBody = rawResponse.body()) {
- if (rawResponseBody == null) {
- throw new RuntimeException("No response");
- }
-
- try (InputStream rawInputStream = rawResponseBody.byteStream()) {
- try (BufferedReader rawReader = new BufferedReader(new InputStreamReader(rawInputStream, StandardCharsets.UTF_8))) {
- return GSON.fromJson(rawReader, JsonObject.class);
- }
- }
- }
- }
- } else {
- String content = permsFile.get("content").getAsString();
- return GSON.fromJson(content, JsonObject.class);
- }
+ return GSON.fromJson(reader, JsonObject.class);
}
}
}
diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java
index 60fbfeb7..b6ea154c 100644
--- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java
+++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/LPNukkitPlugin.java
@@ -103,8 +103,6 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
-import javax.annotation.Nullable;
-
/**
* LuckPerms implementation for the Nukkit API.
*/
@@ -157,7 +155,7 @@ public class LPNukkitPlugin extends PluginBase implements LuckPermsPlugin {
public void onEnable() {
this.startTime = System.currentTimeMillis();
sendStartupBanner(getConsoleSender());
- this.verboseHandler = new VerboseHandler(this.scheduler.asyncNukkit(), getVersion());
+ this.verboseHandler = new VerboseHandler(this.scheduler.asyncNukkit());
this.permissionVault = new PermissionVault(this.scheduler.asyncNukkit());
this.logDispatcher = new LogDispatcher(this);
@@ -469,14 +467,13 @@ public class LPNukkitPlugin extends PluginBase implements LuckPermsPlugin {
return Optional.empty();
}
- @Nullable
@Override
- public Contexts getContextForUser(User user) {
+ public Optional getContextForUser(User user) {
Player player = getPlayer(user);
if (player == null) {
- return null;
+ return Optional.empty();
}
- return this.contextManager.getApplicableContexts(player);
+ return Optional.of(this.contextManager.getApplicableContexts(player));
}
@Override
diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java
index 2371da2b..20c5b365 100644
--- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java
+++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java
@@ -123,8 +123,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.stream.Stream;
-import javax.annotation.Nullable;
-
/**
* LuckPerms implementation for the Sponge API.
*/
@@ -203,7 +201,7 @@ public class LPSpongePlugin implements LuckPermsSpongePlugin {
this.dependencyManager.loadDependencies(DependencyRegistry.GLOBAL_DEPENDENCIES);
sendStartupBanner(getConsoleSender());
- this.verboseHandler = new VerboseHandler(this.scheduler.async(), getVersion());
+ this.verboseHandler = new VerboseHandler(this.scheduler.async());
this.permissionVault = new PermissionVault(this.scheduler.async());
this.logDispatcher = new LogDispatcher(this);
@@ -429,14 +427,13 @@ public class LPSpongePlugin implements LuckPermsSpongePlugin {
}
}
- @Nullable
@Override
- public Contexts getContextForUser(User user) {
+ public Optional getContextForUser(User user) {
Player player = getPlayer(user);
if (player == null) {
- return null;
+ return Optional.empty();
}
- return this.contextManager.getApplicableContexts(player);
+ return Optional.of(this.contextManager.getApplicableContexts(player));
}
@Override