Add user clone command (#530)

This commit is contained in:
Luck
2017-12-17 12:59:36 +00:00
Unverified
parent f86bdb7619
commit fb5925e1e8
17 changed files with 175 additions and 163 deletions
@@ -62,12 +62,7 @@ public class ExtendedLogEntry implements LogEntry {
private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s";
/**
* Compares two LogEntries
*
* @since 3.3
*/
public static final Comparator<LogEntry> COMPARATOR = Comparator
private static final Comparator<LogEntry> COMPARATOR = Comparator
.comparingLong(LogEntry::getTimestamp)
.thenComparing(LogEntry::getActor)
.thenComparing(LogEntry::getActorName, String.CASE_INSENSITIVE_ORDER)
@@ -54,6 +54,7 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@AllArgsConstructor
public class ApiPermissionHolder implements PermissionHolder {
@@ -179,7 +180,7 @@ public class ApiPermissionHolder implements PermissionHolder {
}
@Override
public void clearMatching(Predicate<Node> test) {
public void clearMatching(@NonNull Predicate<Node> test) {
handle.removeIf(test);
if (handle.getType().isUser()) {
handle.getPlugin().getUserManager().giveDefaultIfNeeded((User) handle, false);
@@ -187,7 +188,7 @@ public class ApiPermissionHolder implements PermissionHolder {
}
@Override
public void clearMatchingTransient(Predicate<Node> test) {
public void clearMatchingTransient(@NonNull Predicate<Node> test) {
handle.removeIfTransient(test);
}
@@ -226,11 +227,6 @@ public class ApiPermissionHolder implements PermissionHolder {
handle.clearTransientNodes();
}
@Override
public Set<Node> getTemporaryPermissionNodes() {
return handle.getTemporaryNodes();
}
@Override
public List<LocalizedNode> resolveInheritances(Contexts contexts) {
return handle.resolveInheritances(contexts);
@@ -243,7 +239,12 @@ public class ApiPermissionHolder implements PermissionHolder {
@Override
public Set<Node> getPermanentPermissionNodes() {
return handle.getPermanentNodes();
return handle.getOwnNodes().stream().filter(Node::isPermanent).collect(Collectors.toSet());
}
@Override
public Set<Node> getTemporaryPermissionNodes() {
return handle.getOwnNodes().stream().filter(Node::isPrefix).collect(Collectors.toSet());
}
@Override
@@ -33,6 +33,7 @@ import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.DataMutateResult;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.common.node.NodeFactory;
import java.util.UUID;
@@ -71,7 +72,7 @@ public final class ApiUser extends ApiPermissionHolder implements User {
return DataMutateResult.ALREADY_HAS;
}
if (!handle.hasPermission("group." + s.toLowerCase(), true)) {
if (!handle.hasPermission(NodeFactory.make("group." + s.toLowerCase(), true)).asBoolean()) {
return DataMutateResult.FAIL;
}
@@ -41,6 +41,7 @@ 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.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
@@ -84,7 +85,7 @@ public class ParentAdd extends SharedSubCommand {
return CommandResult.NO_PERMISSION;
}
DataMutateResult result = holder.setInheritGroup(group, context);
DataMutateResult result = holder.setPermission(NodeFactory.newBuilder("group." + group.getName()).withExtraContext(context).build());
if (result.asBoolean()) {
Message.SET_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getFriendlyName(), CommandUtils.contextSetToString(context));
@@ -41,6 +41,7 @@ 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;
@@ -85,7 +86,7 @@ public class ParentSet extends SharedSubCommand {
}
holder.clearParents(context, false);
holder.setInheritGroup(group, context);
holder.setPermission(NodeFactory.newBuilder("group." + group.getName()).withExtraContext(context).build());
if (holder.getType().isUser()) {
((User) holder).getPrimaryGroup().setStoredValue(group.getName());
}
@@ -42,6 +42,7 @@ 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.Track;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
@@ -125,7 +126,7 @@ public class ParentSetTrack extends SharedSubCommand {
}
holder.removeIf(node -> node.isGroupNode() && node.getFullContexts().equals(context) && track.containsGroup(node.getGroupName()));
holder.setInheritGroup(group, context);
holder.setPermission(NodeFactory.newBuilder("group." + group.getName()).withExtraContext(context).build());
Message.SET_TRACK_PARENT_SUCCESS.send(sender, holder.getFriendlyName(), track.getName(), group.getFriendlyName(), CommandUtils.contextSetToString(context));
@@ -78,8 +78,8 @@ public class GroupClone extends SubCommand<Group> {
Message.CLONE_SUCCESS.send(sender, group.getName(), newGroup.getName());
ExtendedLogEntry.build().actor(sender).acted(group)
.action("clone", newGroup.getName())
ExtendedLogEntry.build().actor(sender).acted(newGroup)
.action("clone", group.getName())
.build().submit(plugin, sender);
save(newGroup, sender, plugin);
@@ -63,9 +63,9 @@ public class GroupInfo extends SubCommand<Group> {
group.getWeight().isPresent() ? group.getWeight().getAsInt() : "None",
group.getOwnNodes().size(),
group.getOwnNodes().stream().filter(n -> !(n.isGroupNode() || n.isPrefix() || n.isSuffix() || n.isMeta())).mapToInt(n -> 1).sum(),
group.getPrefixNodes().size(),
group.getSuffixNodes().size(),
group.getMetaNodes().size()
group.getOwnNodes().stream().filter(Node::isPrefix).mapToInt(n -> 1).sum(),
group.getOwnNodes().stream().filter(Node::isSuffix).mapToInt(n -> 1).sum(),
group.getOwnNodes().stream().filter(Node::isMeta).mapToInt(n -> 1).sum()
);
Set<Node> parents = group.getOwnNodesSet().stream()
@@ -0,0 +1,113 @@
/*
* 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.impl.user;
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
import me.lucko.luckperms.common.commands.ArgumentPermissions;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.CommandUtils;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.CommandPermission;
import me.lucko.luckperms.common.constants.DataConstraints;
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.utils.Predicates;
import java.util.List;
import java.util.UUID;
public class UserClone extends SubCommand<User> {
public UserClone(LocaleManager locale) {
super(CommandSpec.USER_CLONE.spec(locale), "clone", CommandPermission.USER_CLONE, Predicates.not(1));
}
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) throws CommandException {
if (ArgumentPermissions.checkViewPerms(plugin, sender, getPermission().get(), user)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
String target = args.get(0);
UUID uuid = CommandUtils.parseUuid(target.toLowerCase());
if (uuid == null) {
if (!plugin.getConfiguration().get(ConfigKeys.ALLOW_INVALID_USERNAMES)) {
if (!DataConstraints.PLAYER_USERNAME_TEST.test(target)) {
Message.USER_INVALID_ENTRY.send(sender, target);
return CommandResult.INVALID_ARGS;
}
} else {
if (!DataConstraints.PLAYER_USERNAME_TEST_LENIENT.test(target)) {
Message.USER_INVALID_ENTRY.send(sender, target);
return CommandResult.INVALID_ARGS;
}
}
uuid = plugin.getStorage().getUUID(target.toLowerCase()).join();
if (uuid == null) {
if (!plugin.getConfiguration().get(ConfigKeys.USE_SERVER_UUID_CACHE)) {
Message.USER_NOT_FOUND.send(sender, target);
return CommandResult.INVALID_ARGS;
}
uuid = plugin.lookupUuid(target).orElse(null);
if (uuid == null) {
Message.USER_NOT_FOUND.send(sender, target);
return CommandResult.INVALID_ARGS;
}
}
}
plugin.getStorage().loadUser(uuid, null).join();
User otherUser = plugin.getUserManager().getIfLoaded(uuid);
if (otherUser == null) {
Message.USER_LOAD_ERROR.send(sender);
return CommandResult.LOADING_ERROR;
}
if (ArgumentPermissions.checkModifyPerms(plugin, sender, getPermission().get(), otherUser)) {
Message.COMMAND_NO_PERMISSION.send(sender);
return CommandResult.NO_PERMISSION;
}
otherUser.replaceEnduringNodes(user.getEnduringNodes());
Message.CLONE_SUCCESS.send(sender, user.getFriendlyName(), otherUser.getFriendlyName());
ExtendedLogEntry.build().actor(sender).acted(otherUser)
.action("clone", user.getName())
.build().submit(plugin, sender);
save(otherUser, sender, plugin);
plugin.getUserManager().cleanup(otherUser);
return CommandResult.SUCCESS;
}
}
@@ -67,9 +67,9 @@ public class UserInfo extends SubCommand<User> {
user.getPrimaryGroup().getValue(),
user.getOwnNodes().size(),
user.getOwnNodes().stream().filter(n -> !(n.isGroupNode() || n.isPrefix() || n.isSuffix() || n.isMeta())).mapToInt(n -> 1).sum(),
user.getPrefixNodes().size(),
user.getSuffixNodes().size(),
user.getMetaNodes().size()
user.getOwnNodes().stream().filter(Node::isPrefix).mapToInt(n -> 1).sum(),
user.getOwnNodes().stream().filter(Node::isSuffix).mapToInt(n -> 1).sum(),
user.getOwnNodes().stream().filter(Node::isMeta).mapToInt(n -> 1).sum()
);
Set<Node> parents = user.getOwnNodesSet().stream()
@@ -76,6 +76,7 @@ public class UserMainCommand extends MainCommand<User, UserIdentifier> {
.add(new UserDemote(locale))
.add(new HolderShowTracks<>(locale, true))
.add(new HolderClear<>(locale, true))
.add(new UserClone(locale))
.build()
);
}
@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.impl.user;
import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.actionlog.ExtendedLogEntry;
import me.lucko.luckperms.common.commands.ArgumentPermissions;
import me.lucko.luckperms.common.commands.CommandException;
@@ -39,6 +38,7 @@ 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.User;
import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates;
@@ -74,7 +74,7 @@ public class UserSwitchPrimaryGroup extends SubCommand<User> {
if (!user.inheritsGroup(group)) {
Message.USER_PRIMARYGROUP_ERROR_NOTMEMBER.send(sender, user.getFriendlyName(), group.getName());
user.setInheritGroup(group, ContextSet.empty());
user.setPermission(NodeFactory.newBuilder("group." + group.getName()).build());
}
user.getPrimaryGroup().setStoredValue(group.getName());
@@ -100,6 +100,7 @@ public enum CommandPermission {
USER_PROMOTE("promote", USER),
USER_DEMOTE("demote", USER),
USER_CLEAR("clear", USER),
USER_CLONE("clone", USER),
GROUP_INFO("info", GROUP),
GROUP_PERM_INFO("permission.info", GROUP),
@@ -148,6 +148,11 @@ public enum CommandSpec {
Arg.create("context...", false, "the contexts to demote the user in")
)
),
USER_CLONE("Clone the user",
Arg.list(
Arg.create("user", true, "the name/uuid of the user to clone onto")
)
),
GROUP_INFO("Gives info about the group"),
GROUP_LISTMEMBERS("Show the users/groups who inherit from this group",
@@ -152,6 +152,7 @@ public enum Message {
ALREADY_EXISTS("&4{}&c already exists!", true),
DOES_NOT_EXIST("&4{}&c does not exist!", true),
USER_LOAD_ERROR("&cAn unexpected error occurred. User not loaded.", true),
GROUP_LOAD_ERROR("&cAn unexpected error occurred. Group not loaded.", true),
GROUPS_LOAD_ERROR("&cAn unexpected error occurred. Unable to load all groups.", true),
@@ -975,30 +975,6 @@ public abstract class PermissionHolder {
return hasPermission(node, false);
}
public boolean hasPermission(String node, boolean value) {
return hasPermission(NodeFactory.make(node, value)).asBoolean() == value;
}
public boolean hasPermission(String node, boolean value, String server) {
return hasPermission(NodeFactory.make(node, value, server)).asBoolean() == value;
}
public boolean hasPermission(String node, boolean value, String server, String world) {
return hasPermission(NodeFactory.make(node, value, server, world)).asBoolean() == value;
}
public boolean hasPermission(String node, boolean value, boolean temporary) {
return hasPermission(NodeFactory.make(node, value, temporary)).asBoolean() == value;
}
public boolean hasPermission(String node, boolean value, String server, boolean temporary) {
return hasPermission(NodeFactory.make(node, value, server, temporary)).asBoolean() == value;
}
public boolean hasPermission(String node, boolean value, String server, String world, boolean temporary) {
return hasPermission(NodeFactory.make(node, value, server, world, temporary)).asBoolean() == value;
}
/**
* Check if the holder inherits a node
*
@@ -1025,30 +1001,6 @@ public abstract class PermissionHolder {
return inheritsPermissionInfo(node).getResult();
}
public boolean inheritsPermission(String node, boolean value) {
return inheritsPermission(NodeFactory.make(node, value)).asBoolean() == value;
}
public boolean inheritsPermission(String node, boolean value, String server) {
return inheritsPermission(NodeFactory.make(node, value, server)).asBoolean() == value;
}
public boolean inheritsPermission(String node, boolean value, String server, String world) {
return inheritsPermission(NodeFactory.make(node, value, server, world)).asBoolean() == value;
}
public boolean inheritsPermission(String node, boolean value, boolean temporary) {
return inheritsPermission(NodeFactory.make(node, value, temporary)).asBoolean() == value;
}
public boolean inheritsPermission(String node, boolean value, String server, boolean temporary) {
return inheritsPermission(NodeFactory.make(node, value, server, temporary)).asBoolean() == value;
}
public boolean inheritsPermission(String node, boolean value, String server, String world, boolean temporary) {
return inheritsPermission(NodeFactory.make(node, value, server, world, temporary)).asBoolean() == value;
}
/**
* Sets a permission node
*
@@ -1201,33 +1153,6 @@ public abstract class PermissionHolder {
return DataMutateResult.SUCCESS;
}
/**
* Unsets a permission node
*
* @param node the node to unset
*/
public DataMutateResult unsetPermissionExact(Node node) {
ImmutableCollection<Node> before = getEnduringNodes().values();
nodesLock.lock();
try {
nodes.get(node.getFullContexts().makeImmutable()).removeIf(e -> e.equals(node));
} finally {
nodesLock.unlock();
}
invalidateCache();
ImmutableCollection<Node> after = getEnduringNodes().values();
if (before.size() == after.size()) {
return DataMutateResult.LACKS;
}
plugin.getApiProvider().getEventFactory().handleNodeRemove(node, this, before, after);
return DataMutateResult.SUCCESS;
}
/**
* Unsets a transient permission node
*
@@ -1255,29 +1180,13 @@ public abstract class PermissionHolder {
}
public boolean inheritsGroup(Group group) {
return group.getName().equalsIgnoreCase(this.getObjectName()) || hasPermission("group." + group.getName(), true);
return group.getName().equalsIgnoreCase(this.getObjectName()) || hasPermission(NodeFactory.make("group." + group.getName(), true)).asBoolean();
}
public boolean inheritsGroup(Group group, ContextSet contextSet) {
return group.getName().equalsIgnoreCase(this.getObjectName()) || hasPermission(NodeFactory.newBuilder("group." + group.getName()).withExtraContext(contextSet).build()).asBoolean();
}
public boolean inheritsGroup(Group group, String server) {
return group.getName().equalsIgnoreCase(this.getObjectName()) || hasPermission("group." + group.getName(), true, server);
}
public boolean inheritsGroup(Group group, String server, String world) {
return group.getName().equalsIgnoreCase(this.getObjectName()) || hasPermission("group." + group.getName(), true, server, world);
}
public DataMutateResult setInheritGroup(Group group, ContextSet contexts) {
return setPermission(NodeFactory.newBuilder("group." + group.getName()).withExtraContext(contexts).build());
}
public DataMutateResult unsetInheritGroup(Group group, ContextSet contexts) {
return unsetPermission(NodeFactory.newBuilder("group." + group.getName()).withExtraContext(contexts).build());
}
/**
* Clear all of the holders permission nodes
*/
@@ -1478,32 +1387,6 @@ public abstract class PermissionHolder {
return true;
}
/**
* @return The temporary nodes held by the holder
*/
public Set<Node> getTemporaryNodes() {
return getOwnNodes().stream().filter(Node::isTemporary).collect(Collectors.toSet());
}
/**
* @return The permanent nodes held by the holder
*/
public Set<Node> getPermanentNodes() {
return getOwnNodes().stream().filter(Node::isPermanent).collect(Collectors.toSet());
}
public Set<Node> getPrefixNodes() {
return getOwnNodes().stream().filter(Node::isPrefix).collect(Collectors.toSet());
}
public Set<Node> getSuffixNodes() {
return getOwnNodes().stream().filter(Node::isSuffix).collect(Collectors.toSet());
}
public Set<Node> getMetaNodes() {
return getOwnNodes().stream().filter(Node::isMeta).collect(Collectors.toSet());
}
public OptionalInt getWeight() {
return weightCache.get();
}