Web editor changes, towards #1703

This commit is contained in:
Luck 2019-08-26 15:03:30 +01:00
parent eff93c788b
commit 5e2f45ebd0
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
25 changed files with 333 additions and 150 deletions

View File

@ -35,6 +35,11 @@ public enum CreationCause {
*/
COMMAND,
/**
* The creation was caused by the web editor
*/
WEB_EDITOR,
/**
* The creation was caused by an API call
*/

View File

@ -100,6 +100,13 @@ public interface Node {
return LuckPermsProvider.get().getNodeBuilderRegistry().forKey(key);
}
/**
* Gets the type of the node.
*
* @return the node type
*/
@NonNull NodeType<?> getType();
/**
* Gets the key ({@link String}) of the node.
*

View File

@ -31,6 +31,7 @@ import me.lucko.luckperms.api.node.metadata.NodeMetadataKey;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.time.temporal.TemporalAccessor;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@ -66,11 +67,20 @@ public interface NodeBuilder<N extends ScopedNode<N, B>, B extends NodeBuilder<N
* <p>The parameter passed to this method must be the unix timestamp
* (in seconds) when the node should expire.</p>
*
* @param expiryUnixTimestamp the expiry timestamp (unix seconds)
* @param expiryEpochSeconds the expiry timestamp (unix seconds)
* @return the builder
* @see Node#getExpiry()
*/
@NonNull B expiry(long expiryUnixTimestamp);
@NonNull B expiry(long expiryEpochSeconds);
/**
* Sets the time when the node should expire.
*
* @param expiry the expiry time
* @return the builder
* @see Node#getExpiry()
*/
@NonNull B expiry(@Nullable TemporalAccessor expiry);
/**
* Sets the time when the node should expire.

View File

@ -36,6 +36,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public interface ScopedNode<N extends ScopedNode<N, B>, B extends NodeBuilder<N, B>> extends Node {
@Override
@NonNull NodeType<N> getType();
@Override
@NonNull B toBuilder();

View File

@ -58,7 +58,7 @@ public interface ChatMetaNode<N extends ChatMetaNode<N, B>, B extends ChatMetaNo
*
* @return the type
*/
@NonNull ChatMetaType getType();
@NonNull ChatMetaType getMetaType();
/**
* A {@link ChatMetaNode} builder.

View File

@ -28,6 +28,7 @@ package me.lucko.luckperms.api.node.types;
import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeBuilder;
import me.lucko.luckperms.api.node.NodeType;
import me.lucko.luckperms.api.node.ScopedNode;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -37,6 +38,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public interface DisplayNameNode extends ScopedNode<DisplayNameNode, DisplayNameNode.Builder> {
@Override
default @NonNull NodeType<DisplayNameNode> getType() {
return NodeType.DISPLAY_NAME;
}
/**
* Gets the display name.
*

View File

@ -29,6 +29,7 @@ import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.model.group.Group;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeBuilder;
import me.lucko.luckperms.api.node.NodeType;
import me.lucko.luckperms.api.node.ScopedNode;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -39,6 +40,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public interface InheritanceNode extends ScopedNode<InheritanceNode, InheritanceNode.Builder> {
@Override
default @NonNull NodeType<InheritanceNode> getType() {
return NodeType.INHERITANCE;
}
/**
* Gets the name of the group to be inherited.
*

View File

@ -28,6 +28,7 @@ package me.lucko.luckperms.api.node.types;
import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeBuilder;
import me.lucko.luckperms.api.node.NodeType;
import me.lucko.luckperms.api.node.ScopedNode;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -37,6 +38,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public interface MetaNode extends ScopedNode<MetaNode, MetaNode.Builder> {
@Override
default @NonNull NodeType<MetaNode> getType() {
return NodeType.META;
}
/**
* Gets the meta key.
*

View File

@ -28,6 +28,7 @@ package me.lucko.luckperms.api.node.types;
import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeBuilder;
import me.lucko.luckperms.api.node.NodeType;
import me.lucko.luckperms.api.node.ScopedNode;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -39,6 +40,11 @@ import java.util.OptionalInt;
*/
public interface PermissionNode extends ScopedNode<PermissionNode, PermissionNode.Builder> {
@Override
default @NonNull NodeType<PermissionNode> getType() {
return NodeType.PERMISSION;
}
/**
* Gets the permission string this node encapsulates.
*

View File

@ -27,6 +27,7 @@ package me.lucko.luckperms.api.node.types;
import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeType;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -35,6 +36,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public interface PrefixNode extends ChatMetaNode<PrefixNode, PrefixNode.Builder> {
@Override
default @NonNull NodeType<PrefixNode> getType() {
return NodeType.PREFIX;
}
/**
* Creates a {@link PrefixNode} builder.
*

View File

@ -28,6 +28,7 @@ package me.lucko.luckperms.api.node.types;
import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeBuilder;
import me.lucko.luckperms.api.node.NodeType;
import me.lucko.luckperms.api.node.ScopedNode;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -40,6 +41,11 @@ import java.util.regex.Pattern;
*/
public interface RegexPermissionNode extends ScopedNode<RegexPermissionNode, RegexPermissionNode.Builder> {
@Override
default @NonNull NodeType<RegexPermissionNode> getType() {
return NodeType.REGEX_PERMISSION;
}
/**
* Gets the non-compiled pattern string.
*

View File

@ -27,6 +27,7 @@ package me.lucko.luckperms.api.node.types;
import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeType;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -35,6 +36,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public interface SuffixNode extends ChatMetaNode<SuffixNode, SuffixNode.Builder> {
@Override
default @NonNull NodeType<SuffixNode> getType() {
return NodeType.SUFFIX;
}
/**
* Creates a {@link SuffixNode} builder.
*

View File

@ -28,6 +28,7 @@ package me.lucko.luckperms.api.node.types;
import me.lucko.luckperms.api.LuckPermsProvider;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeBuilder;
import me.lucko.luckperms.api.node.NodeType;
import me.lucko.luckperms.api.node.ScopedNode;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -37,6 +38,11 @@ import org.checkerframework.checker.nullness.qual.NonNull;
*/
public interface WeightNode extends ScopedNode<WeightNode, WeightNode.Builder> {
@Override
default @NonNull NodeType<WeightNode> getType() {
return NodeType.WEIGHT;
}
/**
* Gets the weight value.
*

View File

@ -174,7 +174,7 @@ public class MetaInfo extends SharedSubCommand {
HoverEvent hoverEvent = HoverEvent.showText(TextUtils.fromLegacy(TextUtils.joinNewline(
"¥3> ¥a" + node.getPriority() + " ¥7- ¥r" + node.getMetaValue(),
" ",
"¥7Click to remove this " + node.getType().name().toLowerCase() + " from " + holder.getFormattedDisplayName()
"¥7Click to remove this " + node.getMetaType().name().toLowerCase() + " from " + holder.getFormattedDisplayName()
), '¥'));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType() == HolderType.GROUP ? holder.getObjectName() : holder.getFormattedDisplayName(), holder.getType(), false, !holder.getPlugin().getConfiguration().getContextsFile().getDefaultContexts().isEmpty());

View File

@ -66,7 +66,7 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
Message.EDITOR_START.send(sender);
// form the payload data
JsonObject payload = WebEditor.formPayload(Collections.singletonList(holder), sender, label, plugin);
JsonObject payload = WebEditor.formPayload(Collections.singletonList(holder), Collections.emptyList(), sender, label, plugin);
// upload the payload data to gist
String pasteId = plugin.getBytebin().postJson(payload, true).id();

View File

@ -30,6 +30,9 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import me.lucko.luckperms.api.actionlog.Action;
import me.lucko.luckperms.api.event.cause.CreationCause;
import me.lucko.luckperms.api.event.cause.DeletionCause;
import me.lucko.luckperms.api.model.DataType;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.common.actionlog.LoggedAction;
@ -42,19 +45,24 @@ import me.lucko.luckperms.common.command.utils.StorageAssistant;
import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.node.model.NodeDataContainer;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.DurationFormatter;
import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.Uuids;
import me.lucko.luckperms.common.web.WebEditor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.UUID;
public class ApplyEditsCommand extends SingleCommand {
public ApplyEditsCommand(LocaleManager locale) {
@ -76,37 +84,75 @@ public class ApplyEditsCommand extends SingleCommand {
return CommandResult.FAILURE;
}
boolean success = false;
if (data.has("tabs") && data.get("tabs").isJsonArray()) {
JsonArray rows = data.get("tabs").getAsJsonArray();
for (JsonElement row : rows) {
if (read(row.getAsJsonObject(), sender, plugin)) {
success = true;
boolean work = false;
if (data.has("changes")) {
JsonArray changes = data.get("changes").getAsJsonArray();
for (JsonElement change : changes) {
if (readChanges(change.getAsJsonObject(), sender, plugin)) {
work = true;
}
}
}
if (data.has("groupDeletions")) {
JsonArray groupDeletions = data.get("groupDeletions").getAsJsonArray();
for (JsonElement groupDeletion : groupDeletions) {
if (readGroupDeletion(groupDeletion, sender, plugin)) {
work = true;
}
}
}
if (data.has("trackDeletions")) {
JsonArray trackDeletions = data.get("trackDeletions").getAsJsonArray();
for (JsonElement trackDeletion : trackDeletions) {
if (readTrackDeletion(trackDeletion, sender, plugin)) {
work = true;
}
}
} else {
success = read(data, sender, plugin);
}
if (!success) {
if (!work) {
Message.APPLY_EDITS_TARGET_NO_CHANGES_PRESENT.send(sender);
}
return CommandResult.SUCCESS;
}
private boolean read(JsonObject data, Sender sender, LuckPermsPlugin plugin) {
if (!data.has("who") || data.get("who").getAsString().isEmpty()) {
Message.APPLY_EDITS_NO_TARGET.send(sender);
private boolean readChanges(JsonObject data, Sender sender, LuckPermsPlugin plugin) {
String type = data.get("type").getAsString();
if (type.equals("user") || type.equals("group")) {
return readHolderChanges(data, sender, plugin);
} else if (type.equals("track")) {
return readTrackChanges(data, sender, plugin);
} else {
Message.APPLY_EDITS_UNKNOWN_TYPE.send(sender, type);
return false;
}
}
String who = data.get("who").getAsString();
PermissionHolder holder = WebEditor.getHolderFromIdentifier(plugin, sender, who);
if (holder == null) {
// the #getHolderFromIdentifier method will send the error message onto the sender
return false;
private boolean readHolderChanges(JsonObject data, Sender sender, LuckPermsPlugin plugin) {
String type = data.get("type").getAsString();
String id = data.get("id").getAsString();
PermissionHolder holder;
if (type.equals("user")) {
// user
UUID uuid = Uuids.parse(id);
if (uuid == null) {
Message.APPLY_EDITS_TARGET_USER_NOT_UUID.send(sender, id);
return false;
}
holder = plugin.getStorage().loadUser(uuid, null).join();
if (holder == null) {
Message.APPLY_EDITS_TARGET_USER_UNABLE_TO_LOAD.send(sender, uuid.toString());
return false;
}
} else {
// group
holder = plugin.getStorage().loadGroup(id).join().orElse(null);
if (holder == null) {
holder = plugin.getStorage().createAndLoadGroup(id, CreationCause.WEB_EDITOR).join();
}
}
if (ArgumentPermissions.checkModifyPerms(plugin, sender, getPermission().get(), holder)) {
@ -114,10 +160,8 @@ public class ApplyEditsCommand extends SingleCommand {
return false;
}
Set<NodeDataContainer> nodes = WebEditor.deserializePermissions(data.getAsJsonArray("nodes"));
Set<Node> before = new HashSet<>(holder.normalData().immutable().values());
Set<Node> after = nodes.stream().map(NodeDataContainer::toNode).collect(Collectors.toSet());
Set<Node> after = new HashSet<>(WebEditor.deserializePermissions(data.getAsJsonArray("nodes")));
Map.Entry<Set<Node>, Set<Node>> diff = diff(before, after);
Set<Node> diffAdded = diff.getKey();
@ -146,7 +190,7 @@ public class ApplyEditsCommand extends SingleCommand {
String additionsSummary = "addition" + (additions == 1 ? "" : "s");
String deletionsSummary = "deletion" + (deletions == 1 ? "" : "s");
Message.APPLY_EDITS_SUCCESS.send(sender, holder.getFormattedDisplayName());
Message.APPLY_EDITS_SUCCESS.send(sender, type, holder.getFormattedDisplayName());
Message.APPLY_EDITS_SUCCESS_SUMMARY.send(sender, additions, additionsSummary, deletions, deletionsSummary);
for (Node n : diffAdded) {
Message.APPLY_EDITS_DIFF_ADDED.send(sender, formatNode(plugin.getLocaleManager(), n));
@ -158,19 +202,125 @@ public class ApplyEditsCommand extends SingleCommand {
return true;
}
private boolean readTrackChanges(JsonObject data, Sender sender, LuckPermsPlugin plugin) {
String id = data.get("id").getAsString();
Track track = plugin.getStorage().loadTrack(id).join().orElse(null);
if (track == null) {
track = plugin.getStorage().createAndLoadTrack(id, CreationCause.WEB_EDITOR).join();
}
Set<String> before = new LinkedHashSet<>(track.getGroups());
Set<String> after = new LinkedHashSet<>();
data.getAsJsonArray("groups").forEach(e -> after.add(e.getAsString()));
Map.Entry<Set<String>, Set<String>> diff = diff(before, after);
Set<String> diffAdded = diff.getKey();
Set<String> diffRemoved = diff.getValue();
int additions = diffAdded.size();
int deletions = diffRemoved.size();
if (additions == 0 && deletions == 0) {
return false;
}
track.setGroups(new ArrayList<>(after));
for (String n : diffAdded) {
LoggedAction.build().source(sender).target(track)
.description("webeditor", "add", n)
.build().submit(plugin, sender);
}
for (String n : diffRemoved) {
LoggedAction.build().source(sender).target(track)
.description("webeditor", "remove", n)
.build().submit(plugin, sender);
}
String additionsSummary = "addition" + (additions == 1 ? "" : "s");
String deletionsSummary = "deletion" + (deletions == 1 ? "" : "s");
Message.APPLY_EDITS_SUCCESS.send(sender, "track", track.getName());
Message.APPLY_EDITS_SUCCESS_SUMMARY.send(sender, additions, additionsSummary, deletions, deletionsSummary);
for (String n : diffAdded) {
Message.APPLY_EDITS_DIFF_ADDED.send(sender, n);
}
for (String n : diffRemoved) {
Message.APPLY_EDITS_DIFF_REMOVED.send(sender, n);
}
StorageAssistant.save(track, sender, plugin);
return true;
}
private boolean readGroupDeletion(JsonElement data, Sender sender, LuckPermsPlugin plugin) {
String groupName = data.getAsString();
if (groupName.equalsIgnoreCase(NodeFactory.DEFAULT_GROUP_NAME)) {
Message.DELETE_GROUP_ERROR_DEFAULT.send(sender);
return true;
}
Group group = plugin.getStorage().loadGroup(groupName).join().orElse(null);
if (group == null) {
return false;
}
try {
plugin.getStorage().deleteGroup(group, DeletionCause.COMMAND).get();
} catch (Exception e) {
e.printStackTrace();
Message.DELETE_ERROR.send(sender, group.getFormattedDisplayName());
return true;
}
Message.DELETE_SUCCESS.send(sender, group.getFormattedDisplayName());
LoggedAction.build().source(sender).targetName(groupName).targetType(Action.Target.Type.GROUP)
.description("webeditor", "delete")
.build().submit(plugin, sender);
return true;
}
private boolean readTrackDeletion(JsonElement data, Sender sender, LuckPermsPlugin plugin) {
String trackName = data.getAsString();
Track track = plugin.getStorage().loadTrack(trackName).join().orElse(null);
if (track == null) {
return false;
}
try {
plugin.getStorage().deleteTrack(track, DeletionCause.COMMAND).get();
} catch (Exception e) {
e.printStackTrace();
Message.DELETE_ERROR.send(sender, track.getName());
return true;
}
Message.DELETE_SUCCESS.send(sender, trackName);
LoggedAction.build().source(sender).targetName(trackName).targetType(Action.Target.Type.TRACK)
.description("webeditor", "delete")
.build().submit(plugin, sender);
return true;
}
private static String formatNode(LocaleManager localeManager, Node n) {
return n.getKey() + " &7(" + (n.getValue() ? "&a" : "&c") + n.getValue() + "&7)" + MessageUtils.getAppendableNodeContextString(localeManager, n) +
(n.hasExpiry() ? " &7(" + DurationFormatter.CONCISE.formatDateDiff(n.getExpiry().getEpochSecond()) + ")" : "");
}
private static Map.Entry<Set<Node>, Set<Node>> diff(Set<Node> before, Set<Node> after) {
private static <T> Map.Entry<Set<T>, Set<T>> diff(Set<T> before, Set<T> after) {
// entries in before but not after are being removed
// entries in after but not before are being added
Set<Node> added = new HashSet<>(after);
Set<T> added = new LinkedHashSet<>(after);
added.removeAll(before);
Set<Node> removed = new HashSet<>(before);
Set<T> removed = new LinkedHashSet<>(before);
removed.removeAll(after);
return Maps.immutableEntry(added, removed);

View File

@ -37,6 +37,7 @@ import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.command.CommandSpec;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Predicates;
@ -72,6 +73,7 @@ public class EditorCommand extends SingleCommand {
// collect holders
List<PermissionHolder> holders = new ArrayList<>();
List<Track> tracks = new ArrayList<>();
if (type.includingGroups) {
plugin.getGroupManager().getAll().values().stream()
.sorted((o1, o2) -> {
@ -79,6 +81,7 @@ public class EditorCommand extends SingleCommand {
return i != 0 ? i : o1.getName().compareToIgnoreCase(o2.getName());
})
.forEach(holders::add);
tracks = new ArrayList<>(plugin.getTrackManager().getAll().values());
}
if (type.includingUsers) {
plugin.getUserManager().getAll().values().stream()
@ -93,9 +96,10 @@ public class EditorCommand extends SingleCommand {
// remove holders which the sender doesn't have perms to view
holders.removeIf(holder -> ArgumentPermissions.checkViewPerms(plugin, sender, getPermission().get(), holder));
tracks.removeIf(track -> ArgumentPermissions.checkViewPerms(plugin, sender, getPermission().get(), track));
// they don't have perms to view any of them
if (holders.isEmpty()) {
if (holders.isEmpty() && tracks.isEmpty()) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
@ -103,7 +107,7 @@ public class EditorCommand extends SingleCommand {
Message.EDITOR_START.send(sender);
// form the payload data
JsonObject payload = WebEditor.formPayload(holders, sender, label, plugin);
JsonObject payload = WebEditor.formPayload(holders, tracks, sender, label, plugin);
// upload the payload data to gist
String pasteId = plugin.getBytebin().postJson(payload, true).id();

View File

@ -152,13 +152,12 @@ public enum Message {
APPLY_EDITS_INVALID_CODE("&cInvalid code. &7({})", true),
APPLY_EDITS_UNABLE_TO_READ("&cUnable to read data using the given code. &7({})", true),
APPLY_EDITS_NO_TARGET("&cUnable to parse the target of the edit.", true),
APPLY_EDITS_TARGET_GROUP_NOT_EXISTS("&cTarget group &4{}&c does not exist.", true),
APPLY_EDITS_UNKNOWN_TYPE("&cUnable to apply edit to the specified object type. &7({})", true),
APPLY_EDITS_TARGET_USER_NOT_UUID("&cTarget user &4{}&c is not a valid uuid.", true),
APPLY_EDITS_TARGET_USER_UNABLE_TO_LOAD("&cUnable to load target user &4{}&c.", true),
APPLY_EDITS_TARGET_UNKNOWN("&cInvalid target. &7({})", true),
APPLY_EDITS_TARGET_NO_CHANGES_PRESENT("&aNo changes were applied from the web editor. The returned data didn't contain any edits.", true),
APPLY_EDITS_SUCCESS("&aWeb editor data was applied to &b{}&a successfully.", true),
APPLY_EDITS_SUCCESS("&aWeb editor data was applied to {} &b{}&a successfully.", true),
APPLY_EDITS_SUCCESS_SUMMARY("&7(&a{} &7{} and &c{} &7{})", true),
APPLY_EDITS_DIFF_ADDED("&a+ &f{}", false),
APPLY_EDITS_DIFF_REMOVED("&c- &f{}", false),

View File

@ -87,7 +87,7 @@ public final class Track implements Identifiable<String> {
@Override
public String getId() {
return this.name.toLowerCase();
return getName();
}
/**

View File

@ -35,6 +35,8 @@ import me.lucko.luckperms.api.node.metadata.NodeMetadataKey;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Objects;
@ -72,8 +74,18 @@ public abstract class AbstractNodeBuilder<N extends ScopedNode<N, B>, B extends
}
@Override
public @NonNull B expiry(long expiryUnixTimestamp) {
this.expireAt = expiryUnixTimestamp;
public @NonNull B expiry(long expiryEpochSeconds) {
this.expireAt = expiryEpochSeconds;
return (B) this;
}
@Override
public @NonNull B expiry(@Nullable TemporalAccessor expiry) {
if (expiry == null) {
return clearExpiry();
}
this.expireAt = expiry.getLong(ChronoField.INSTANT_SECONDS);
return (B) this;
}

View File

@ -161,7 +161,7 @@ public final class NodeFactory {
sb.append("temp");
}
sb.append(cmNode.getType().toString())
sb.append(cmNode.getMetaType().toString())
.append(" ")
.append(cmNode.getPriority()) // weight
.append(" ");

View File

@ -59,7 +59,7 @@ public class Prefix extends AbstractNode<PrefixNode, PrefixNode.Builder> impleme
}
@Override
public @NonNull ChatMetaType getType() {
public @NonNull ChatMetaType getMetaType() {
return ChatMetaType.PREFIX;
}

View File

@ -59,7 +59,7 @@ public class Suffix extends AbstractNode<SuffixNode, SuffixNode.Builder> impleme
}
@Override
public @NonNull ChatMetaType getType() {
public @NonNull ChatMetaType getMetaType() {
return ChatMetaType.SUFFIX;
}

View File

@ -665,7 +665,7 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
attributes.getNode("priority").setValue(chatMeta.getPriority());
writeAttributesTo(attributes, node, false);
switch (chatMeta.getType()) {
switch (chatMeta.getMetaType()) {
case PREFIX:
appendNode(prefixesSection, chatMeta.getMetaValue(), attributes, "prefix");
break;

View File

@ -30,17 +30,14 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import me.lucko.luckperms.api.context.ImmutableContextSet;
import me.lucko.luckperms.api.node.Node;
import me.lucko.luckperms.api.node.NodeBuilder;
import me.lucko.luckperms.common.context.ContextSetJsonSerializer;
import me.lucko.luckperms.common.locale.message.Message;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.model.NodeDataContainer;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.node.factory.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Uuids;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.util.gson.JArray;
import me.lucko.luckperms.common.util.gson.JObject;
@ -54,11 +51,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Stream;
/**
* Utility methods for interacting with the LuckPerms web permission editor.
@ -66,42 +63,49 @@ import java.util.stream.Stream;
public final class WebEditor {
private WebEditor() {}
private static final String USER_ID_PATTERN = "user/";
private static final String GROUP_ID_PATTERN = "group/";
private static JObject writeData(PermissionHolder holder) {
return new JObject()
.add("who", new JObject()
.add("id", getHolderIdentifier(holder))
.add("friendly", holder.getPlainDisplayName())
.consume(obj -> {
if (holder.getType() == HolderType.USER) {
obj.add("uuid", ((User) holder).getUuid().toString());
}
}))
.add("nodes", serializePermissions(holder.normalData().immutable().values().stream().map(NodeDataContainer::fromNode)));
.add("type", holder.getType().toString())
.add("id", holder.getObjectName())
.add("displayName", holder.getPlainDisplayName())
.add("nodes", serializePermissions(holder.normalData().immutable().values()));
}
public static JsonObject formPayload(List<PermissionHolder> holders, Sender sender, String cmdLabel, LuckPermsPlugin plugin) {
private static JObject writeData(Track track) {
return new JObject()
.add("type", "track")
.add("id", track.getName())
.add("groups", new JArray().consume(a -> track.getGroups().forEach(a::add)));
}
public static JsonObject formPayload(List<PermissionHolder> holders, List<Track> tracks, Sender sender, String cmdLabel, LuckPermsPlugin plugin) {
Preconditions.checkArgument(!holders.isEmpty(), "holders is empty");
// form the payload data
return new JObject()
.add("metadata", new JObject()
.add("cmdAlias", cmdLabel)
.add("commandAlias", cmdLabel)
.add("uploader", new JObject()
.add("name", sender.getNameWithLocation())
.add("uuid", sender.getUuid().toString())
)
.add("time", System.currentTimeMillis())
.add("pluginVersion", plugin.getBootstrap().getVersion())
)
.add("sessions", new JArray()
.add("permissionHolders", new JArray()
.consume(arr -> {
for (PermissionHolder holder : holders) {
arr.add(writeData(holder));
}
})
)
.add("tracks", new JArray()
.consume(arr -> {
for (Track track : tracks) {
arr.add(writeData(track));
}
})
)
.add("knownPermissions", new JArray()
.consume(arr -> {
for (String perm : plugin.getPermissionRegistry().rootAsList()) {
@ -111,42 +115,6 @@ public final class WebEditor {
).toJson();
}
private static String getHolderIdentifier(PermissionHolder holder) {
if (holder.getType() == HolderType.USER) {
User user = ((User) holder);
return USER_ID_PATTERN + user.getUuid().toString();
} else {
Group group = ((Group) holder);
return GROUP_ID_PATTERN + group.getName();
}
}
public static PermissionHolder getHolderFromIdentifier(LuckPermsPlugin plugin, Sender sender, String who) {
if (who.startsWith(GROUP_ID_PATTERN)) {
String group = who.substring(GROUP_ID_PATTERN.length());
Group holder = plugin.getStorage().loadGroup(group).join().orElse(null);
if (holder == null) {
Message.APPLY_EDITS_TARGET_GROUP_NOT_EXISTS.send(sender, group);
}
return holder;
} else if (who.startsWith(USER_ID_PATTERN)) {
String user = who.substring(USER_ID_PATTERN.length());
UUID uuid = Uuids.parse(user);
if (uuid == null) {
Message.APPLY_EDITS_TARGET_USER_NOT_UUID.send(sender, user);
return null;
}
User holder = plugin.getStorage().loadUser(uuid, null).join();
if (holder == null) {
Message.APPLY_EDITS_TARGET_USER_UNABLE_TO_LOAD.send(sender, uuid.toString());
}
return holder;
} else {
Message.APPLY_EDITS_TARGET_UNKNOWN.send(sender, who);
return null;
}
}
public static JsonObject readDataFromBytebin(Bytebin bytebin, String id) {
Request request = new Request.Builder()
.url(bytebin.getPasteUrl(id))
@ -169,23 +137,18 @@ public final class WebEditor {
}
}
private static JsonArray serializePermissions(Stream<NodeDataContainer> nodes) {
private static JsonArray serializePermissions(Collection<Node> nodes) {
JsonArray arr = new JsonArray();
nodes.forEach(node -> {
for (Node node : nodes) {
JsonObject attributes = new JsonObject();
attributes.addProperty("permission", node.getPermission());
attributes.addProperty("type", node.getType().name().toLowerCase());
attributes.addProperty("key", node.getKey());
attributes.addProperty("value", node.getValue());
if (!node.getServer().equals("global")) {
attributes.addProperty("server", node.getServer());
}
if (!node.getWorld().equals("global")) {
attributes.addProperty("world", node.getWorld());
}
if (node.getExpiry() != 0L) {
attributes.addProperty("expiry", node.getExpiry());
Instant expiry = node.getExpiry();
if (expiry != null) {
attributes.addProperty("expiry", expiry.getEpochSecond());
}
if (!node.getContexts().isEmpty()) {
@ -193,48 +156,30 @@ public final class WebEditor {
}
arr.add(attributes);
});
}
return arr;
}
public static Set<NodeDataContainer> deserializePermissions(JsonArray permissionsSection) {
Set<NodeDataContainer> nodes = new HashSet<>();
public static Set<Node> deserializePermissions(JsonArray arr) {
Set<Node> nodes = new HashSet<>();
for (JsonElement ent : arr) {
JsonObject attributes = ent.getAsJsonObject();
for (JsonElement ent : permissionsSection) {
if (!ent.isJsonObject()) {
continue;
String key = attributes.get("key").getAsString();
boolean value = attributes.get("value").getAsBoolean();
NodeBuilder<?, ?> builder = NodeFactory.builder(key).value(value);
if (attributes.has("expiry")) {
builder.expiry(attributes.get("expiry").getAsLong());
}
JsonObject data = ent.getAsJsonObject();
String permission = data.get("permission").getAsString();
boolean value = true;
String server = "global";
String world = "global";
long expiry = 0L;
ImmutableContextSet context = ImmutableContextSet.empty();
if (data.has("value")) {
value = data.get("value").getAsBoolean();
}
if (data.has("server")) {
server = data.get("server").getAsString();
}
if (data.has("world")) {
world = data.get("world").getAsString();
}
if (data.has("expiry")) {
expiry = data.get("expiry").getAsLong();
if (attributes.has("context")) {
builder.context(ContextSetJsonSerializer.deserializeContextSet(attributes.get("context")));
}
if (data.has("context") && data.get("context").isJsonObject()) {
JsonObject contexts = data.get("context").getAsJsonObject();
context = ContextSetJsonSerializer.deserializeContextSet(contexts).immutableCopy();
}
nodes.add(NodeDataContainer.of(permission, value, server, world, expiry, context));
nodes.add(builder.build());
}
return nodes;
}