Refactor paginated command output, add flags for ordering 'permission info' entries, fix crashes caused by long messages (#591)

This commit is contained in:
Luck 2017-12-16 21:05:43 +00:00
parent 2e7a08c006
commit 904bb90385
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
29 changed files with 447 additions and 403 deletions

View File

@ -302,7 +302,7 @@ public class VaultChatHook extends Chat {
world = perms.correctWorld(world);
Contexts contexts;
if (holder instanceof User) {
if (holder.getType().isUser()) {
contexts = perms.createContextForWorldLookup(perms.getPlugin().getPlayer((User) holder), world);
} else {
contexts = perms.createContextForWorldLookup(world);
@ -322,7 +322,7 @@ public class VaultChatHook extends Chat {
world = perms.correctWorld(world);
Contexts contexts;
if (holder instanceof User) {
if (holder.getType().isUser()) {
contexts = perms.createContextForWorldLookup(perms.getPlugin().getPlayer((User) holder), world);
} else {
contexts = perms.createContextForWorldLookup(world);

View File

@ -444,11 +444,11 @@ public class VaultPermissionHook extends Permission {
}
void holderSave(PermissionHolder holder) {
if (holder instanceof User) {
if (holder.getType().isUser()) {
User u = (User) holder;
plugin.getStorage().saveUser(u).thenRunAsync(() -> u.getRefreshBuffer().request(), plugin.getScheduler().async());
}
if (holder instanceof Group) {
if (holder.getType().isGroup()) {
Group g = (Group) holder;
plugin.getStorage().saveGroup(g).thenRunAsync(() -> plugin.getUpdateTaskBuffer().request(), plugin.getScheduler().async());
}

View File

@ -283,11 +283,11 @@ public class ExtendedLogEntry implements LogEntry {
}
public ExtendedLogEntryBuilder acted(PermissionHolder acted) {
if (acted instanceof User) {
if (acted.getType().isUser()) {
actedName(((User) acted).getName().orElse("null"));
acted(((User) acted).getUuid());
type(Type.USER);
} else if (acted instanceof Group) {
} else if (acted.getType().isGroup()) {
actedName(((Group) acted).getName());
type(Type.GROUP);
}

View File

@ -66,7 +66,7 @@ public class ApiPermissionHolder implements PermissionHolder {
@Override
public String getFriendlyName() {
if (handle instanceof Group) {
if (handle.getType().isGroup()) {
Group group = (Group) this.handle;
return group.getDisplayName().orElse(group.getName());
}
@ -181,7 +181,7 @@ public class ApiPermissionHolder implements PermissionHolder {
@Override
public void clearMatching(Predicate<Node> test) {
handle.removeIf(test);
if (handle instanceof User) {
if (handle.getType().isUser()) {
handle.getPlugin().getUserManager().giveDefaultIfNeeded((User) handle, false);
}
}

View File

@ -35,6 +35,7 @@ import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.utils.Cycle;
@ -124,7 +125,7 @@ public class Exporter implements Runnable {
write(writer, "# Export group: " + group.getName());
for (Node node : group.getEnduringNodes().values()) {
write(writer, "/lp " + NodeFactory.nodeAsCommand(node, group.getName(), true, true));
write(writer, "/lp " + NodeFactory.nodeAsCommand(node, group.getName(), HolderType.GROUP, true));
}
write(writer, "");
log.logAllProgress("Exported {} groups so far.", groupCount.incrementAndGet());
@ -230,7 +231,7 @@ public class Exporter implements Runnable {
continue;
}
output.add("/lp " + NodeFactory.nodeAsCommand(node, user.getUuid().toString(), false, true));
output.add("/lp " + NodeFactory.nodeAsCommand(node, user.getUuid().toString(), HolderType.USER, true));
}
if (!user.getPrimaryGroup().getStoredValue().orElse("default").equalsIgnoreCase("default")) {

View File

@ -118,13 +118,13 @@ public abstract class SharedSubCommand {
}
public static void save(PermissionHolder holder, Sender sender, LuckPermsPlugin plugin) {
if (holder instanceof User) {
if (holder.getType().isUser()) {
User user = ((User) holder);
SubCommand.save(user, sender, plugin);
return;
}
if (holder instanceof Group) {
if (holder.getType().isGroup()) {
Group group = ((Group) holder);
SubCommand.save(group, sender, plugin);
return;

View File

@ -43,7 +43,6 @@ import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
@ -168,12 +167,12 @@ public class MetaInfo extends SharedSubCommand {
"¥7Click to remove this " + type.name().toLowerCase() + " from " + holder.getFriendlyName()
), '¥'));
boolean group = !(holder instanceof User);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, group ? holder.getObjectName() : holder.getFriendlyName(), group, false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType().isGroup() ? holder.getObjectName() : holder.getFriendlyName(), holder.getType(), false);
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> {
component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command));
component.clickEvent(clickEvent);
};
}
@ -192,12 +191,12 @@ public class MetaInfo extends SharedSubCommand {
"¥7Click to remove this meta pair from " + holder.getFriendlyName()
), '¥'));
boolean group = !(holder instanceof User);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, group ? holder.getObjectName() : holder.getFriendlyName(), group, false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType().isGroup() ? holder.getObjectName() : holder.getFriendlyName(), holder.getType(), false);
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> {
component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command));
component.clickEvent(clickEvent);
};
}
}

View File

@ -71,7 +71,7 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
JsonObject payload = new JsonObject();
payload.addProperty("who", WebEditorUtils.getHolderIdentifier(holder));
payload.addProperty("whoFriendly", holder.getFriendlyName());
if (holder instanceof User) {
if (holder.getType().isUser()) {
payload.addProperty("whoUuid", ((User) holder).getUuid().toString());
}
payload.addProperty("cmdAlias", label);

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.common.commands.impl.generic.other;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.commands.ArgumentPermissions;
import me.lucko.luckperms.common.commands.CommandException;
@ -37,10 +39,13 @@ 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.PermissionHolder;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@ -63,32 +68,32 @@ public class HolderShowTracks<T extends PermissionHolder> extends SubCommand<T>
Set<Node> nodes = holder.getEnduringNodes().values().stream()
.filter(Node::isGroupNode)
.filter(Node::getValuePrimitive)
.filter(Node::isPermanent)
.collect(Collectors.toSet());
StringBuilder sb = new StringBuilder();
List<Map.Entry<Track, String>> lines = new ArrayList<>();
for (Node node : nodes) {
String name = node.getGroupName();
plugin.getTrackManager().getAll().values().stream()
List<Track> tracks = plugin.getTrackManager().getAll().values().stream()
.filter(t -> t.containsGroup(name))
.forEach(t -> sb.append("&a")
.append(t.getName())
.append(": ")
.append(CommandUtils.listToArrowSep(t.getGroups(), name))
.append(CommandUtils.getAppendableNodeContextString(node))
.append("\n")
);
.collect(Collectors.toList());
for (Track t : tracks) {
lines.add(Maps.immutableEntry(t, CommandUtils.listToArrowSep(t.getGroups(), name) + CommandUtils.getAppendableNodeContextString(node)));
}
}
if (sb.length() == 0) {
if (lines.isEmpty()) {
Message.LIST_TRACKS_EMPTY.send(sender, holder.getFriendlyName());
return CommandResult.SUCCESS;
} else {
sb.deleteCharAt(sb.length() - 1);
Message.LIST_TRACKS.send(sender, holder.getFriendlyName(), sb.toString());
return CommandResult.SUCCESS;
}
Message.LIST_TRACKS.send(sender, holder.getFriendlyName());
for (Map.Entry<Track, String> line : lines) {
Message.LIST_TRACKS_ENTRY.send(sender, line.getKey().getName(), line.getValue());
}
return CommandResult.SUCCESS;
}
}

View File

@ -103,7 +103,7 @@ public class ParentClearTrack extends SharedSubCommand {
holder.removeIf(node -> node.isGroupNode() && node.getFullContexts().equals(context) && track.containsGroup(node.getGroupName()));
}
if (holder instanceof User) {
if (holder.getType().isUser()) {
plugin.getUserManager().giveDefaultIfNeeded(((User) holder), false);
}

View File

@ -32,35 +32,38 @@ import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.CommandUtils;
import me.lucko.luckperms.common.commands.utils.SortMode;
import me.lucko.luckperms.common.commands.utils.SortType;
import me.lucko.luckperms.common.constants.CommandPermission;
import me.lucko.luckperms.common.constants.Constants;
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.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.NodeWithContextComparator;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.CollationKeyCache;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.function.Consumer;
public class ParentInfo extends SharedSubCommand {
public ParentInfo(LocaleManager locale) {
super(CommandSpec.PARENT_INFO.spec(locale), "info", CommandPermission.USER_PARENT_INFO, CommandPermission.GROUP_PARENT_INFO, Predicates.alwaysFalse());
super(CommandSpec.PARENT_INFO.spec(locale), "info", CommandPermission.USER_PARENT_INFO, CommandPermission.GROUP_PARENT_INFO, Predicates.notInRange(0, 2));
}
@Override
@ -70,58 +73,67 @@ public class ParentInfo extends SharedSubCommand {
return CommandResult.NO_PERMISSION;
}
Component ent = permGroupsToMessage(holder.getOwnNodesSorted(), holder, label);
Message.LISTPARENTS.send(sender, holder.getFriendlyName());
sender.sendMessage(ent);
int page = ArgumentUtils.handleIntOrElse(0, args, 1);
SortMode sortMode = SortMode.determine(args);
Component tempEnt = tempGroupsToMessage(holder.getOwnNodesSorted(), holder, label);
Message.LISTPARENTS_TEMP.send(sender, holder.getFriendlyName());
sender.sendMessage(tempEnt);
// get the holders nodes
List<LocalizedNode> nodes = new ArrayList<>(holder.getOwnNodesSorted());
// remove irrelevant types (these are displayed in the other info commands)
nodes.removeIf(node -> !node.isGroupNode() || !node.getValuePrimitive());
// handle empty
if (nodes.isEmpty()) {
Message.PARENT_INFO_NO_DATA.send(sender, holder.getFriendlyName());
return CommandResult.SUCCESS;
}
// sort the list alphabetically instead
if (sortMode.getType() == SortType.ALPHABETICALLY) {
nodes.sort(ALPHABETICAL_NODE_COMPARATOR);
}
// reverse the order if necessary
if (!sortMode.isAscending()) {
Collections.reverse(nodes);
}
int pageIndex = page - 1;
List<List<LocalizedNode>> pages = CommandUtils.divideList(nodes, 19);
if (pageIndex < 0 || pageIndex >= pages.size()) {
page = 1;
pageIndex = 0;
}
List<LocalizedNode> content = pages.get(pageIndex);
// send header
Message.PARENT_INFO.send(sender, holder.getFriendlyName(), page, pages.size(), nodes.size());
// send content
for (LocalizedNode node : content) {
String s = "&3> &a" + node.getGroupName() + CommandUtils.getAppendableNodeContextString(node);
if (node.isTemporary()) {
s += "\n&2 expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime());
}
TextComponent message = TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build();
sender.sendMessage(message);
}
return CommandResult.SUCCESS;
}
private static Component permGroupsToMessage(SortedSet<LocalizedNode> nodes, PermissionHolder holder, String label) {
List<Node> page = new ArrayList<>();
for (Node node : nodes) {
if (!node.isGroupNode()) continue;
if (!node.getValuePrimitive()) continue;
if (node.isTemporary()) continue;
page.add(node);
private static final Comparator<LocalizedNode> ALPHABETICAL_NODE_COMPARATOR = (o1, o2) -> {
int i = CollationKeyCache.compareStrings(o1.getGroupName(), o2.getGroupName());
if (i != 0) {
return i;
}
if (page.isEmpty()) {
return TextComponent.builder("None").color(TextColor.DARK_AQUA).build();
}
TextComponent.Builder message = TextComponent.builder("");
for (Node node : page) {
String s = "&3> &a" + node.getGroupName() + CommandUtils.getAppendableNodeContextString(node) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build());
}
return message.build();
}
private static Component tempGroupsToMessage(SortedSet<LocalizedNode> nodes, PermissionHolder holder, String label) {
List<Node> page = new ArrayList<>();
for (Node node : nodes) {
if (!node.isGroupNode()) continue;
if (!node.getValuePrimitive()) continue;
if (node.isPermanent()) continue;
page.add(node);
}
if (page.isEmpty()) {
return TextComponent.builder("None").color(TextColor.DARK_AQUA).build();
}
TextComponent.Builder message = TextComponent.builder("");
for (Node node : page) {
String s = "&3> &a" + node.getGroupName() + CommandUtils.getAppendableNodeContextString(node) + "\n&2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build());
}
return message.build();
}
// fallback to priority
return NodeWithContextComparator.reverse().compare(o1, o2);
};
private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(PermissionHolder holder, String label, Node node) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
@ -130,12 +142,12 @@ public class ParentInfo extends SharedSubCommand {
"&7Click to remove this parent from " + holder.getFriendlyName()
), Constants.FORMAT_CHAR));
boolean group = !(holder instanceof User);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, group ? holder.getObjectName() : holder.getFriendlyName(), group, false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType().isGroup() ? holder.getObjectName() : holder.getFriendlyName(), holder.getType(), false);
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> {
component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command));
component.clickEvent(clickEvent);
};
}
}

View File

@ -75,7 +75,7 @@ public class ParentRemove extends SharedSubCommand {
return CommandResult.NO_PERMISSION;
}
if (holder instanceof User) {
if (holder.getType().isUser()) {
User user = (User) holder;
boolean shouldPrevent = plugin.getConfiguration().get(ConfigKeys.PREVENT_PRIMARY_GROUP_REMOVAL) &&
@ -97,7 +97,7 @@ public class ParentRemove extends SharedSubCommand {
.action("parent", "remove", groupName, context)
.build().submit(plugin, sender);
if (holder instanceof User) {
if (holder.getType().isUser()) {
plugin.getUserManager().giveDefaultIfNeeded(((User) holder), false);
}

View File

@ -86,7 +86,7 @@ public class ParentSet extends SharedSubCommand {
holder.clearParents(context, false);
holder.setInheritGroup(group, context);
if (holder instanceof User) {
if (holder.getType().isUser()) {
((User) holder).getPrimaryGroup().setStoredValue(group.getName());
}

View File

@ -25,8 +25,6 @@
package me.lucko.luckperms.common.commands.impl.generic.permission;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.commands.ArgumentPermissions;
@ -36,30 +34,31 @@ import me.lucko.luckperms.common.commands.abstraction.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.CommandUtils;
import me.lucko.luckperms.common.commands.utils.SortMode;
import me.lucko.luckperms.common.commands.utils.SortType;
import me.lucko.luckperms.common.constants.CommandPermission;
import me.lucko.luckperms.common.constants.Constants;
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.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.NodeWithContextComparator;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.CollationKeyCache;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.function.Consumer;
public class PermissionInfo extends SharedSubCommand {
@ -74,111 +73,72 @@ public class PermissionInfo extends SharedSubCommand {
return CommandResult.NO_PERMISSION;
}
String filter = null;
if (args.size() == 1) {
// it might be a filter, if it's a number, then it relates to a page.
try {
Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
// it's not a number, so assume it's the filter.
filter = args.get(0);
}
} else if (args.size() == 2) {
filter = args.get(1);
}
int page = ArgumentUtils.handleIntOrElse(0, args, 1);
SortMode sortMode = SortMode.determine(args);
Map.Entry<Component, String> ent = nodesToMessage(false, filter, holder.getOwnNodesSorted(), holder, label, page, sender.isConsole());
if (ent.getValue() != null) {
Message.LISTNODES_WITH_PAGE.send(sender, holder.getFriendlyName(), ent.getValue());
sender.sendMessage(ent.getKey());
} else {
Message.LISTNODES.send(sender, holder.getFriendlyName());
sender.sendMessage(ent.getKey());
// get the holders nodes
List<LocalizedNode> nodes = new ArrayList<>(holder.getOwnNodesSorted());
// remove irrelevant types (these are displayed in the other info commands)
nodes.removeIf(node ->
// remove if the node is a group node, and if the value isn't false and if the group actually exists
(node.isGroupNode() && node.getValuePrimitive() && plugin.getGroupManager().isLoaded(node.getGroupName())) ||
// remove if the node is a meta node
node.isPrefix() || node.isSuffix() || node.isMeta()
);
// handle empty
if (nodes.isEmpty()) {
Message.PERMISSION_INFO_NO_DATA.send(sender, holder.getFriendlyName());
return CommandResult.SUCCESS;
}
Map.Entry<Component, String> tempEnt = nodesToMessage(true, filter, holder.getOwnNodesSorted(), holder, label, page, sender.isConsole());
if (tempEnt.getValue() != null) {
Message.LISTNODES_TEMP_WITH_PAGE.send(sender, holder.getFriendlyName(), tempEnt.getValue());
sender.sendMessage(tempEnt.getKey());
} else {
Message.LISTNODES_TEMP.send(sender, holder.getFriendlyName());
sender.sendMessage(tempEnt.getKey());
// sort the list alphabetically instead
if (sortMode.getType() == SortType.ALPHABETICALLY) {
nodes.sort(ALPHABETICAL_NODE_COMPARATOR);
}
// reverse the order if necessary
if (!sortMode.isAscending()) {
Collections.reverse(nodes);
}
int pageIndex = page - 1;
List<List<LocalizedNode>> pages = CommandUtils.divideList(nodes, 19);
if (pageIndex < 0 || pageIndex >= pages.size()) {
page = 1;
pageIndex = 0;
}
List<LocalizedNode> content = pages.get(pageIndex);
// send header
Message.PERMISSION_INFO.send(sender, holder.getFriendlyName(), page, pages.size(), nodes.size());
// send content
for (LocalizedNode node : content) {
String s = "&3> " + (node.getValuePrimitive() ? "&a" : "&c") + node.getPermission() + (sender.isConsole() ? " &7(" + node.getValuePrimitive() + "&7)" : "") + CommandUtils.getAppendableNodeContextString(node);
if (node.isTemporary()) {
s += "\n&2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime());
}
TextComponent message = TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build();
sender.sendMessage(message);
}
return CommandResult.SUCCESS;
}
private static Map.Entry<Component, String> nodesToMessage(boolean temp, String filter, SortedSet<LocalizedNode> nodes, PermissionHolder holder, String label, int pageNumber, boolean console) {
// parse the filter
String nodeFilter = null;
Map.Entry<String, String> contextFilter = null;
if (filter != null) {
int index = filter.indexOf('=');
context:
if (index != -1) {
String key = filter.substring(0, index);
if (key.equals("")) break context;
String value = filter.substring(index + 1);
if (value.equals("")) break context;
contextFilter = Maps.immutableEntry(key, value);
}
if (contextFilter == null) {
nodeFilter = filter;
}
private static final Comparator<LocalizedNode> ALPHABETICAL_NODE_COMPARATOR = (o1, o2) -> {
int i = CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission());
if (i != 0) {
return i;
}
List<Node> l = new ArrayList<>();
for (Node node : nodes) {
if ((node.isGroupNode() && node.getValuePrimitive()) || node.isPrefix() || node.isSuffix() || node.isMeta()) continue;
// check against filters
if (nodeFilter != null && !node.getPermission().startsWith(nodeFilter)) continue;
if (contextFilter != null && !node.getFullContexts().hasIgnoreCase(contextFilter.getKey(), contextFilter.getValue())) continue;
if (temp != node.isTemporary()) continue;
l.add(node);
}
if (l.isEmpty()) {
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
}
int index = pageNumber - 1;
List<List<Node>> pages = CommandUtils.divideList(l, 15);
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<Node> page = pages.get(index);
TextComponent.Builder message = TextComponent.builder("");
String title = "&7(showing page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + l.size() + "&7 entries";
if (filter != null) {
title += " - filtered by &f\"" + filter + "\"&7)";
} else {
title += ")";
}
for (Node node : page) {
String s = "&3> " + (node.getValuePrimitive() ? "&a" : "&c") + node.getPermission() + (console ? " &7(" + node.getValuePrimitive() + "&7)" : "") + CommandUtils.getAppendableNodeContextString(node) + "\n";
if (temp) {
s += "&2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "\n";
}
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build());
}
return Maps.immutableEntry(message.build(), title);
}
// fallback to priority
return NodeWithContextComparator.reverse().compare(o1, o2);
};
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(PermissionHolder holder, String label, Node node) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
@ -187,12 +147,12 @@ public class PermissionInfo extends SharedSubCommand {
"¥7Click to remove this node from " + holder.getFriendlyName()
), '¥'));
boolean group = !(holder instanceof User);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, group ? holder.getObjectName() : holder.getFriendlyName(), group, false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType().isGroup() ? holder.getObjectName() : holder.getFriendlyName(), holder.getType(), false);
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> {
component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command));
component.clickEvent(clickEvent);
};
}
}

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.common.commands.impl.group;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.HeldPermission;
@ -44,20 +46,17 @@ import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ -90,96 +89,60 @@ public class GroupListMembers extends SubCommand<Group> {
Message.SEARCH_RESULT.send(sender, users + groups, users, groups);
Map<UUID, String> uuidLookups = new HashMap<>();
Function<UUID, String> lookupFunc = uuid -> uuidLookups.computeIfAbsent(uuid, u -> {
String s = plugin.getStorage().getName(u).join();
if (s == null || s.isEmpty() || s.equals("null")) {
s = u.toString();
}
return s;
});
Map.Entry<Component, String> msgUsers = searchUserResultToMessage(matchedUsers, lookupFunc, label, page);
Map.Entry<Component, String> msgGroups = searchGroupResultToMessage(matchedGroups, label, page);
if (msgUsers.getValue() != null) {
Message.SEARCH_SHOWING_USERS_WITH_PAGE.send(sender, msgUsers.getValue());
sender.sendMessage(msgUsers.getKey());
} else {
Message.SEARCH_SHOWING_USERS.send(sender);
sender.sendMessage(msgUsers.getKey());
if (!matchedUsers.isEmpty()) {
LoadingCache<UUID, String> uuidLookups = Caffeine.newBuilder()
.build(u -> {
String s = plugin.getStorage().getName(u).join();
if (s == null || s.isEmpty() || s.equals("null")) {
s = u.toString();
}
return s;
});
sendResult(sender, matchedUsers, uuidLookups::get, Message.SEARCH_SHOWING_USERS, HolderType.USER, label, page);
}
if (msgGroups.getValue() != null) {
Message.SEARCH_SHOWING_GROUPS_WITH_PAGE.send(sender, msgGroups.getValue());
sender.sendMessage(msgGroups.getKey());
} else {
Message.SEARCH_SHOWING_GROUPS.send(sender);
sender.sendMessage(msgGroups.getKey());
if (!matchedGroups.isEmpty()) {
sendResult(sender, matchedGroups, Function.identity(), Message.SEARCH_SHOWING_GROUPS, HolderType.GROUP, label, page);
}
return CommandResult.SUCCESS;
}
private static Map.Entry<Component, String> searchUserResultToMessage(List<HeldPermission<UUID>> results, Function<UUID, String> uuidLookup, String label, int pageNumber) {
if (results.isEmpty()) {
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
private static <T> void sendResult(Sender sender, List<HeldPermission<T>> results, Function<T, String> lookupFunction, Message headerMessage, HolderType holderType, String label, int page) {
results = new ArrayList<>(results);
// we need a deterministic sort order
// even though we're comparing uuids here in some cases - it doesn't matter
// the import thing is that the order is the same each time the command is executed
results.sort((o1, o2) -> {
Comparable h1 = (Comparable) o1.getHolder();
Comparable h2 = (Comparable) o2.getHolder();
//noinspection unchecked
return h1.compareTo(h2);
});
int pageIndex = page - 1;
List<List<HeldPermission<T>>> pages = CommandUtils.divideList(results, 15);
if (pageIndex < 0 || pageIndex >= pages.size()) {
page = 1;
pageIndex = 0;
}
List<HeldPermission<UUID>> sorted = new ArrayList<>(results);
sorted.sort(Comparator.comparing(HeldPermission::getHolder));
List<HeldPermission<T>> content = pages.get(pageIndex);
int index = pageNumber - 1;
List<List<HeldPermission<UUID>>> pages = CommandUtils.divideList(sorted, 15);
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<HeldPermission<UUID>> page = pages.get(index);
List<Map.Entry<String, HeldPermission<UUID>>> uuidMappedPage = page.stream()
.map(hp -> Maps.immutableEntry(uuidLookup.apply(hp.getHolder()), hp))
List<Map.Entry<String, HeldPermission<T>>> mappedContent = content.stream()
.map(hp -> Maps.immutableEntry(lookupFunction.apply(hp.getHolder()), hp))
.collect(Collectors.toList());
TextComponent.Builder message = TextComponent.builder("");
String title = "&7(page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + sorted.size() + "&7 entries)";
// send header
headerMessage.send(sender, page, pages.size(), results.size());
for (Map.Entry<String, HeldPermission<UUID>> ent : uuidMappedPage) {
String s = "&3> &b" + ent.getKey() + " " + getNodeExpiryString(ent.getValue().asNode()) + CommandUtils.getAppendableNodeContextString(ent.getValue().asNode()) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), false, label, ent.getValue())).build());
for (Map.Entry<String, HeldPermission<T>> ent : mappedContent) {
String s = "&3> &b" + ent.getKey() + " " + getNodeExpiryString(ent.getValue().asNode()) + CommandUtils.getAppendableNodeContextString(ent.getValue().asNode());
TextComponent message = TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue())).build();
sender.sendMessage(message);
}
return Maps.immutableEntry(message.build(), title);
}
private static Map.Entry<Component, String> searchGroupResultToMessage(List<HeldPermission<String>> results, String label, int pageNumber) {
if (results.isEmpty()) {
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
}
List<HeldPermission<String>> sorted = new ArrayList<>(results);
sorted.sort(Comparator.comparing(HeldPermission::getHolder));
int index = pageNumber - 1;
List<List<HeldPermission<String>>> pages = CommandUtils.divideList(sorted, 15);
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<HeldPermission<String>> page = pages.get(index);
TextComponent.Builder message = TextComponent.builder("");
String title = "&7(page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + sorted.size() + "&7 entries)";
for (HeldPermission<String> ent : page) {
String s = "&3> &b" + ent.getHolder() + " " + getNodeExpiryString(ent.asNode()) + CommandUtils.getAppendableNodeContextString(ent.asNode()) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getHolder(), true, label, ent)).build());
}
return Maps.immutableEntry(message.build(), title);
}
private static String getNodeExpiryString(Node node) {
@ -190,18 +153,19 @@ public class GroupListMembers extends SubCommand<Group> {
return " &8(&7expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "&8)";
}
private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(String holderName, boolean group, String label, HeldPermission<?> perm) {
private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(String holderName, HolderType holderType, String label, HeldPermission<?> perm) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
"&3> " + (perm.asNode().getValuePrimitive() ? "&a" : "&c") + perm.asNode().getGroupName(),
"&3> &b" + perm.asNode().getGroupName(),
" ",
"&7Click to remove this parent from " + holderName
), Constants.FORMAT_CHAR));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, group, false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, holderType, false);
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> {
component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command));
component.clickEvent(clickEvent);
};
}
}

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.common.commands.impl.misc;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.HeldPermission;
@ -43,20 +45,17 @@ import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.BuildableComponent;
import net.kyori.text.Component;
import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@ -84,32 +83,20 @@ public class SearchCommand extends SingleCommand {
Message.SEARCH_RESULT.send(sender, users + groups, users, groups);
Map<UUID, String> uuidLookups = new HashMap<>();
Function<UUID, String> lookupFunc = uuid -> uuidLookups.computeIfAbsent(uuid, u -> {
String s = plugin.getStorage().getName(u).join();
if (s == null || s.isEmpty() || s.equals("null")) {
s = u.toString();
}
return s;
});
Map.Entry<Component, String> msgUsers = searchUserResultToMessage(matchedUsers, lookupFunc, label, page);
Map.Entry<Component, String> msgGroups = searchGroupResultToMessage(matchedGroups, label, page);
if (msgUsers.getValue() != null) {
Message.SEARCH_SHOWING_USERS_WITH_PAGE.send(sender, msgUsers.getValue());
sender.sendMessage(msgUsers.getKey());
} else {
Message.SEARCH_SHOWING_USERS.send(sender);
sender.sendMessage(msgUsers.getKey());
if (!matchedUsers.isEmpty()) {
LoadingCache<UUID, String> uuidLookups = Caffeine.newBuilder()
.build(u -> {
String s = plugin.getStorage().getName(u).join();
if (s == null || s.isEmpty() || s.equals("null")) {
s = u.toString();
}
return s;
});
sendResult(sender, matchedUsers, uuidLookups::get, Message.SEARCH_SHOWING_USERS, HolderType.USER, label, page);
}
if (msgGroups.getValue() != null) {
Message.SEARCH_SHOWING_GROUPS_WITH_PAGE.send(sender, msgGroups.getValue());
sender.sendMessage(msgGroups.getKey());
} else {
Message.SEARCH_SHOWING_GROUPS.send(sender);
sender.sendMessage(msgGroups.getKey());
if (!matchedGroups.isEmpty()) {
sendResult(sender, matchedGroups, Function.identity(), Message.SEARCH_SHOWING_GROUPS, HolderType.GROUP, label, page);
}
return CommandResult.SUCCESS;
@ -120,65 +107,41 @@ public class SearchCommand extends SingleCommand {
return SubCommand.getPermissionTabComplete(args, plugin.getPermissionVault());
}
private static Map.Entry<Component, String> searchUserResultToMessage(List<HeldPermission<UUID>> results, Function<UUID, String> uuidLookup, String label, int pageNumber) {
if (results.isEmpty()) {
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
private static <T> void sendResult(Sender sender, List<HeldPermission<T>> results, Function<T, String> lookupFunction, Message headerMessage, HolderType holderType, String label, int page) {
results = new ArrayList<>(results);
// we need a deterministic sort order
// even though we're comparing uuids here in some cases - it doesn't matter
// the import thing is that the order is the same each time the command is executed
results.sort((o1, o2) -> {
Comparable h1 = (Comparable) o1.getHolder();
Comparable h2 = (Comparable) o2.getHolder();
//noinspection unchecked
return h1.compareTo(h2);
});
int pageIndex = page - 1;
List<List<HeldPermission<T>>> pages = CommandUtils.divideList(results, 15);
if (pageIndex < 0 || pageIndex >= pages.size()) {
page = 1;
pageIndex = 0;
}
List<HeldPermission<UUID>> sorted = new ArrayList<>(results);
sorted.sort(Comparator.comparing(HeldPermission::getHolder));
List<HeldPermission<T>> content = pages.get(pageIndex);
int index = pageNumber - 1;
List<List<HeldPermission<UUID>>> pages = CommandUtils.divideList(sorted, 15);
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<HeldPermission<UUID>> page = pages.get(index);
List<Map.Entry<String, HeldPermission<UUID>>> uuidMappedPage = page.stream()
.map(hp -> Maps.immutableEntry(uuidLookup.apply(hp.getHolder()), hp))
List<Map.Entry<String, HeldPermission<T>>> mappedContent = content.stream()
.map(hp -> Maps.immutableEntry(lookupFunction.apply(hp.getHolder()), hp))
.collect(Collectors.toList());
TextComponent.Builder message = TextComponent.builder("");
String title = "&7(page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + sorted.size() + "&7 entries)";
// send header
headerMessage.send(sender, page, pages.size(), results.size());
for (Map.Entry<String, HeldPermission<UUID>> ent : uuidMappedPage) {
String s = "&3> &b" + ent.getKey() + " &7- " + (ent.getValue().getValue() ? "&a" : "&c") + ent.getValue().getValue() + getNodeExpiryString(ent.getValue().asNode()) + CommandUtils.getAppendableNodeContextString(ent.getValue().asNode()) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), false, label, ent.getValue())).build());
for (Map.Entry<String, HeldPermission<T>> ent : mappedContent) {
String s = "&3> &b" + ent.getKey() + " &7- " + (ent.getValue().getValue() ? "&a" : "&c") + ent.getValue().getValue() + getNodeExpiryString(ent.getValue().asNode()) + CommandUtils.getAppendableNodeContextString(ent.getValue().asNode());
TextComponent message = TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue())).build();
sender.sendMessage(message);
}
return Maps.immutableEntry(message.build(), title);
}
private static Map.Entry<Component, String> searchGroupResultToMessage(List<HeldPermission<String>> results, String label, int pageNumber) {
if (results.isEmpty()) {
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
}
List<HeldPermission<String>> sorted = new ArrayList<>(results);
sorted.sort(Comparator.comparing(HeldPermission::getHolder));
int index = pageNumber - 1;
List<List<HeldPermission<String>>> pages = CommandUtils.divideList(sorted, 15);
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<HeldPermission<String>> page = pages.get(index);
TextComponent.Builder message = TextComponent.builder("");
String title = "&7(page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + sorted.size() + "&7 entries)";
for (HeldPermission<String> ent : page) {
String s = "&3> &b" + ent.getHolder() + " &7- " + (ent.getValue() ? "&a" : "&c") + ent.getValue() + getNodeExpiryString(ent.asNode()) + CommandUtils.getAppendableNodeContextString(ent.asNode()) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getHolder(), true, label, ent)).build());
}
return Maps.immutableEntry(message.build(), title);
}
private static String getNodeExpiryString(Node node) {
@ -189,18 +152,19 @@ public class SearchCommand extends SingleCommand {
return " &8(&7expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "&8)";
}
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(String holderName, boolean group, String label, HeldPermission<?> perm) {
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(String holderName, HolderType holderType, String label, HeldPermission<?> perm) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
"&3> " + (perm.asNode().getValuePrimitive() ? "&a" : "&c") + perm.asNode().getPermission(),
" ",
"&7Click to remove this node from " + holderName
), Constants.FORMAT_CHAR));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, group, false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, holderType, false);
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> {
component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command));
component.clickEvent(clickEvent);
};
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
*
* 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.commands.utils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
@Getter
@AllArgsConstructor
public class SortMode {
public static SortMode determine(List<String> args) {
SortType type = SortType.PRIORITY;
boolean ascending = true;
for (String arg : args) {
if (arg.equals("!") || arg.equalsIgnoreCase("reverse") || arg.equalsIgnoreCase("reversed")) {
ascending = false;
} else if (arg.equalsIgnoreCase("priority")) {
type = SortType.PRIORITY;
ascending = true;
} else if (arg.equalsIgnoreCase("!priority")) {
type = SortType.PRIORITY;
ascending = false;
} else if (arg.equalsIgnoreCase("alphabetically") || arg.equalsIgnoreCase("abc")) {
type = SortType.ALPHABETICALLY;
ascending = true;
} else if (arg.equalsIgnoreCase("!alphabetically") || arg.equalsIgnoreCase("!abc")) {
type = SortType.ALPHABETICALLY;
ascending = false;
} else {
continue;
}
break;
}
return new SortMode(type, ascending);
}
private final SortType type;
private final boolean ascending;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
*
* 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.commands.utils;
public enum SortType {
PRIORITY,
ALPHABETICALLY;
@Override
public String toString() {
return name().toLowerCase();
}
}

View File

@ -191,7 +191,7 @@ public enum CommandSpec {
PERMISSION_INFO("Lists the permission nodes the object has",
Arg.list(
Arg.create("page", false, "the page to view"),
Arg.create("filter", false, "the string to filter by")
Arg.create("sort mode", false, "how to sort the entries")
)
),
PERMISSION_SET("Sets a permission for the object",
@ -234,7 +234,12 @@ public enum CommandSpec {
)
),
PARENT_INFO("Lists the groups that this object inherits from"),
PARENT_INFO("Lists the groups that this object inherits from",
Arg.list(
Arg.create("page", false, "the page to view"),
Arg.create("sort mode", false, "how to sort the entries")
)
),
PARENT_SET("Removes all other groups the object inherits already and adds them to the one given",
Arg.list(
Arg.create("group", true, "the group to set to"),

View File

@ -113,10 +113,9 @@ public enum Message {
SEARCH_SEARCHING("&aSearching for users and groups with &b{}&a...", true),
SEARCH_SEARCHING_MEMBERS("&aSearching for users and groups who inherit from &b{}&a...", true),
SEARCH_RESULT("&aFound &b{}&a entries from &b{}&a users and &b{}&a groups.", true),
SEARCH_SHOWING_USERS("&bShowing user entries:", true),
SEARCH_SHOWING_GROUPS("&bShowing group entries:", true),
SEARCH_SHOWING_USERS_WITH_PAGE("&bShowing user entries: {}", true),
SEARCH_SHOWING_GROUPS_WITH_PAGE("&bShowing group entries: {}", true),
SEARCH_SHOWING_USERS("&bShowing user entries: &7(showing page &f{}&7 of &f{}&7 - &f{}&7 entries)", true),
SEARCH_SHOWING_GROUPS("&bShowing group entries: &7(showing page &f{}&7 of &f{}&7 - &f{}&7 entries)", true),
APPLY_EDITS_INVALID_CODE("&cInvalid code. &7({})", true),
APPLY_EDITS_UNABLE_TO_READ("&cUnable to read data using the given code. &7({})", true),
@ -198,14 +197,14 @@ public enum Message {
TRACKS_LIST("&aTracks: {}", true),
LISTNODES("&b{}'s Permissions:", true),
LISTNODES_WITH_PAGE("&b{}'s Permissions: {}", true),
LISTNODES_TEMP("&b{}'s Temporary Permissions:", true),
LISTNODES_TEMP_WITH_PAGE("&b{}'s Temporary Permissions: {}", true),
PERMISSION_INFO("&b{}'s Permissions: &7(showing page &f{}&7 of &f{}&7 - &f{}&7 entries)", true),
PERMISSION_INFO_NO_DATA("&b{}&a does not have any permissions set.", true),
LISTPARENTS("&b{}'s Parent Groups:", true),
LISTPARENTS_TEMP("&b{}'s Temporary Parent Groups:", true),
LIST_TRACKS("&b{}'s Tracks:" + "\n" + "{}", true),
PARENT_INFO("&b{}'s Parents: &7(showing page &f{}&7 of &f{}&7 - &f{}&7 entries)", true),
PARENT_INFO_NO_DATA("&b{}&a does not have any parents defined.", true),
LIST_TRACKS("&b{}'s Tracks:", true),
LIST_TRACKS_ENTRY("&a{}: {}", false),
LIST_TRACKS_EMPTY("&b{}&a is not on any tracks.", true),
CONTEXT_PAIR_INLINE("&3{}=&b{}", false),

View File

@ -37,6 +37,7 @@ import me.lucko.luckperms.common.caching.GroupCachedData;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.GroupReference;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.references.Identifiable;
import java.util.Optional;
@ -111,6 +112,11 @@ public class Group extends PermissionHolder implements Identifiable<String> {
return GroupReference.of(getId());
}
@Override
public HolderType getType() {
return HolderType.GROUP;
}
private CompletableFuture<Void> reloadCachedData() {
return CompletableFuture.allOf(cachedData.reloadPermissions(), cachedData.reloadMeta()).thenAccept(n -> {
getPlugin().getApiProvider().getEventFactory().handleGroupDataRecalculate(this, cachedData);

View File

@ -64,6 +64,7 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.primarygroup.GroupInheritanceComparator;
import me.lucko.luckperms.common.references.GroupReference;
import me.lucko.luckperms.common.references.HolderReference;
import me.lucko.luckperms.common.references.HolderType;
import java.util.ArrayList;
import java.util.Collection;
@ -240,7 +241,7 @@ public abstract class PermissionHolder {
protected void declareState() {
/* only declare state of groups. the state manager isn't really being used now the caches in this class
are gone, but it's useful for command output. */
if (this instanceof Group) {
if (this.getType().isGroup()) {
plugin.getCachedStateManager().putAll(toReference(), getGroupReferences());
}
}
@ -268,6 +269,13 @@ public abstract class PermissionHolder {
*/
public abstract HolderReference<?, ?> toReference();
/**
* Returns the type of this PermissionHolder.
*
* @return this holders type
*/
public abstract HolderType getType();
/**
* Gets the API delegate for this instance
*
@ -543,7 +551,7 @@ public abstract class PermissionHolder {
excludedGroups = new HashSet<>();
}
if (this instanceof Group) {
if (this.getType().isGroup()) {
excludedGroups.add(getObjectName().toLowerCase());
}
@ -619,7 +627,7 @@ public abstract class PermissionHolder {
excludedGroups = new HashSet<>();
}
if (this instanceof Group) {
if (this.getType().isGroup()) {
excludedGroups.add(getObjectName().toLowerCase());
}
@ -768,7 +776,7 @@ public abstract class PermissionHolder {
excludedGroups = new HashSet<>();
}
if (this instanceof Group) {
if (this.getType().isGroup()) {
excludedGroups.add(getObjectName().toLowerCase());
}
@ -830,7 +838,7 @@ public abstract class PermissionHolder {
excludedGroups = new HashSet<>();
}
if (this instanceof Group) {
if (this.getType().isGroup()) {
excludedGroups.add(getObjectName().toLowerCase());
}
@ -956,7 +964,7 @@ public abstract class PermissionHolder {
* @return a tristate
*/
public Tristate hasPermission(Node node, boolean checkTransient) {
if (this instanceof Group && node.isGroupNode() && node.getGroupName().equalsIgnoreCase(getObjectName())) {
if (this.getType().isGroup() && node.isGroupNode() && node.getGroupName().equalsIgnoreCase(getObjectName())) {
return Tristate.TRUE;
}
@ -1327,7 +1335,7 @@ public abstract class PermissionHolder {
nodesLock.unlock();
}
if (this instanceof User && giveDefault) {
if (this.getType().isUser() && giveDefault) {
plugin.getUserManager().giveDefaultIfNeeded((User) this, false);
}
@ -1355,7 +1363,7 @@ public abstract class PermissionHolder {
nodesLock.unlock();
}
if (this instanceof User && giveDefault) {
if (this.getType().isUser() && giveDefault) {
plugin.getUserManager().giveDefaultIfNeeded((User) this, false);
}
invalidateCache();
@ -1501,7 +1509,7 @@ public abstract class PermissionHolder {
}
private OptionalInt calculateWeight() {
if (this instanceof User) return OptionalInt.empty();
if (this.getType().isUser()) return OptionalInt.empty();
boolean seen = false;
int best = 0;

View File

@ -36,6 +36,7 @@ import me.lucko.luckperms.common.caching.UserCachedData;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.primarygroup.PrimaryGroupHolder;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.references.Identifiable;
import me.lucko.luckperms.common.references.UserIdentifier;
import me.lucko.luckperms.common.references.UserReference;
@ -168,6 +169,11 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
return UserReference.of(getId());
}
@Override
public HolderType getType() {
return HolderType.USER;
}
/**
* Sets up the UserData cache
* Blocking call.

View File

@ -34,6 +34,7 @@ import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.utils.PatternCache;
import java.util.Iterator;
@ -79,9 +80,9 @@ public class NodeFactory {
return new NodeBuilder("suffix." + priority + "." + LegacyNodeFactory.escapeCharacters(suffix));
}
public static String nodeAsCommand(Node node, String id, boolean group, boolean set) {
public static String nodeAsCommand(Node node, String id, HolderType type, boolean set) {
StringBuilder sb = new StringBuilder();
sb.append(group ? "group " : "user ").append(id).append(" ");
sb.append(type.toString()).append(" ").append(id).append(" ");
if (node.isGroupNode()) {
sb.append(node.isTemporary() ? (set ? "parent addtemp " : "parent removetemp ") : (set ? "parent add " : "parent remove "));
@ -95,16 +96,16 @@ public class NodeFactory {
}
if (node.getValuePrimitive() && (node.isPrefix() || node.isSuffix())) {
ChatMetaType type = node.isPrefix() ? ChatMetaType.PREFIX : ChatMetaType.SUFFIX;
ChatMetaType nodeType = node.isPrefix() ? ChatMetaType.PREFIX : ChatMetaType.SUFFIX;
String typeName = type.name().toLowerCase();
sb.append(node.isTemporary() ? (set ? "meta addtemp" + typeName + " " : "meta removetemp" + typeName + " ") : (set ? "meta add" + typeName + " " : "meta remove" + typeName + " "));
sb.append(type.getEntry(node).getKey()).append(" ");
sb.append(nodeType.getEntry(node).getKey()).append(" ");
if (type.getEntry(node).getValue().contains(" ")) {
sb.append("\"").append(type.getEntry(node).getValue()).append("\"");
if (nodeType.getEntry(node).getValue().contains(" ")) {
sb.append("\"").append(nodeType.getEntry(node).getValue()).append("\"");
} else {
sb.append(type.getEntry(node).getValue());
sb.append(nodeType.getEntry(node).getValue());
}
if (set && node.isTemporary()) {
sb.append(" ").append(node.getExpiryUnixTime());

View File

@ -42,7 +42,7 @@ public class GroupInheritanceComparator implements Comparator<Group> {
private static final Comparator<Group> NULL_ORIGIN = new GroupInheritanceComparator(null);
public static Comparator<Group> getFor(PermissionHolder origin) {
if (origin instanceof User) {
if (origin.getType().isUser()) {
return new GroupInheritanceComparator(((User) origin));
}
return NULL_ORIGIN;

View File

@ -25,9 +25,27 @@
package me.lucko.luckperms.common.references;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.common.model.PermissionHolder;
@Getter
@AllArgsConstructor
public enum HolderType {
USER,
GROUP
USER(true, false),
GROUP(false, true);
private final boolean user;
private final boolean group;
public boolean matches(PermissionHolder holder) {
return holder.getType() == this;
}
@Override
public String toString() {
return name().toLowerCase();
}
}

View File

@ -70,7 +70,7 @@ public class WebEditorUtils {
private static final String GROUP_ID_PATTERN = "group/";
public static String getHolderIdentifier(PermissionHolder holder) {
if (holder instanceof User) {
if (holder.getType().isUser()) {
User user = ((User) holder);
return USER_ID_PATTERN + user.getUuid().toString();
} else {

View File

@ -48,7 +48,7 @@ import java.util.Set;
public class SpongeMigrationUtils {
public static void migrateSubject(Subject from, PermissionHolder to, int priority) {
if (to instanceof Group) {
if (to.getType().isGroup()) {
MigrationUtils.setGroupWeight((Group) to, priority);
}

View File

@ -133,7 +133,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
return CompletableFuture.completedFuture(false);
}
if (holder instanceof User) {
if (holder.getType().isUser()) {
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
}
@ -158,7 +158,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
return CompletableFuture.completedFuture(false);
}
if (holder instanceof User) {
if (holder.getType().isUser()) {
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
}
@ -251,7 +251,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
toRemove.forEach(makeUnsetConsumer(false));
ret = !toRemove.isEmpty();
if (ret && holder instanceof User) {
if (ret && holder.getType().isUser()) {
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
}
}
@ -277,7 +277,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
toRemove.forEach(makeUnsetConsumer(false));
ret = !toRemove.isEmpty();
if (ret && holder instanceof User) {
if (ret && holder.getType().isUser()) {
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
}
}
@ -441,14 +441,14 @@ public class LuckPermsSubjectData implements LPSubjectData {
private CompletableFuture<Void> objectSave(PermissionHolder t) {
if (!enduring) {
// don't bother saving to primary storage. just refresh
if (t instanceof User) {
if (t.getType().isUser()) {
User user = ((User) t);
return user.getRefreshBuffer().request();
} else {
return service.getPlugin().getUpdateTaskBuffer().request();
}
} else {
if (t instanceof User) {
if (t.getType().isUser()) {
User user = ((User) t);
return service.getPlugin().getStorage().saveUser(user).thenComposeAsync(success -> {
if (!success) {