Add user clone command (#530)

This commit is contained in:
Luck 2017-12-17 12:59:36 +00:00
parent f86bdb7619
commit fb5925e1e8
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
17 changed files with 175 additions and 163 deletions

View File

@ -2,8 +2,8 @@
# Locale: en_US (English) # Locale: en_US (English)
# Author: Luck # Author: Luck
prefix: "&7&l[&b&lL&3&lP&7&l] &c" prefix: "&7&l[&b&lL&3&lP&7&l] "
empty: "{0}" empty: "&c{0}"
player-online: "&aOnline" player-online: "&aOnline"
player-offline: "&cOffline" player-offline: "&cOffline"
loading-error: "&cPermissions data could not be loaded. Please try again later." loading-error: "&cPermissions data could not be loaded. Please try again later."
@ -45,10 +45,8 @@ tree-url: "&aPermission tree URL:"
search-searching: "&aSearching for users and groups with &b{0}&a..." search-searching: "&aSearching for users and groups with &b{0}&a..."
search-searching-members: "&aSearching for users and groups who inherit from &b{0}&a..." search-searching-members: "&aSearching for users and groups who inherit from &b{0}&a..."
search-result: "&aFound &b{0}&a entries from &b{1}&a users and &b{2}&a groups." search-result: "&aFound &b{0}&a entries from &b{1}&a users and &b{2}&a groups."
search-showing-users: "&bShowing user entries:" search-showing-users: "&bShowing user entries: &7(showing page &f{0}&7 of &f{1}&7 - &f{2}&7 entries)"
search-showing-groups: "&bShowing group entries:" search-showing-groups: "&bShowing group entries: &7(showing page &f{0}&7 of &f{1}&7 - &f{2}&7 entries)"
search-showing-users-with-page: "&bShowing user entries: {0}"
search-showing-groups-with-page: "&bShowing group entries: {0}"
apply-edits-invalid-code: "&cInvalid code. &7({0})" apply-edits-invalid-code: "&cInvalid code. &7({0})"
apply-edits-unable-to-read: "&cUnable to read data using the given code. &7({0})" apply-edits-unable-to-read: "&cUnable to read data using the given code. &7({0})"
apply-edits-no-target: "&cUnable to parse the target of the edit. Please supply it as an extra argument." apply-edits-no-target: "&cUnable to parse the target of the edit. Please supply it as an extra argument."
@ -60,8 +58,9 @@ apply-edits-success: "&aWeb editor data was applied to &b{0}&a successfully."
apply-edits-success-summary: "&7(&a{0} &7{1} and &c{2} &7{3})" apply-edits-success-summary: "&7(&a{0} &7{1} and &c{2} &7{3})"
apply-edits-diff-added: "&a+ &f{0}" apply-edits-diff-added: "&a+ &f{0}"
apply-edits-diff-removed: "&c- &f{0}" apply-edits-diff-removed: "&c- &f{0}"
editor-start: "&7Preparing a new editor sesssion. Please wait..."
editor-upload-failure: "&cUnable to upload permission data to the editor." editor-upload-failure: "&cUnable to upload permission data to the editor."
editor-url: "&aEditor URL:" editor-url: "&aClick the link below to open the editor:"
check-result: "&aPermission check result on user &b{0}&a for permission &b{1}&a: &f{2}" check-result: "&aPermission check result on user &b{0}&a for permission &b{1}&a: &f{2}"
create-success: "&b{0}&a was successfully created." create-success: "&b{0}&a was successfully created."
delete-success: "&b{0}&a was successfully deleted." delete-success: "&b{0}&a was successfully deleted."
@ -76,6 +75,7 @@ track-does-not-contain: "&b{0}&a doesn't contain &b{1}&a."
track-ambiguous-call: "&4{0}&c is a member of multiple groups on this track. Unable to determine their location." track-ambiguous-call: "&4{0}&c is a member of multiple groups on this track. Unable to determine their location."
already-exists: "&4{0}&c already exists!" already-exists: "&4{0}&c already exists!"
does-not-exist: "&4{0}&c does not exist!" does-not-exist: "&4{0}&c does not exist!"
user-load-error: "&cAn unexpected error occurred. User not loaded."
group-load-error: "&cAn unexpected error occurred. Group not loaded." group-load-error: "&cAn unexpected error occurred. Group not loaded."
groups-load-error: "&cAn unexpected error occurred. Unable to load all groups." groups-load-error: "&cAn unexpected error occurred. Unable to load all groups."
track-load-error: "&cAn unexpected error occurred. Track not loaded." track-load-error: "&cAn unexpected error occurred. Track not loaded."
@ -111,15 +111,12 @@ groups-list: "&aGroups: &7(name, weight, tracks)"
groups-list-entry: "&f- &3{0} &7- &b{1}" groups-list-entry: "&f- &3{0} &7- &b{1}"
groups-list-entry-with-tracks: "&f- &3{0} &7- &b{1} &7- [&3{2}&7]" groups-list-entry-with-tracks: "&f- &3{0} &7- &b{1} &7- [&3{2}&7]"
tracks-list: "&aTracks: {0}" tracks-list: "&aTracks: {0}"
listnodes: "&b{0}'s Permissions:" permission-info: "&b{0}'s Permissions: &7(showing page &f{1}&7 of &f{2}&7 - &f{3}&7 entries)"
listnodes-with-page: "&b{0}'s Permissions: {1}" permission-info-no-data: "&b{0}&a does not have any permissions set."
listnodes-temp: "&b{0}'s Temporary Permissions:" parent-info: "&b{0}'s Parents: &7(showing page &f{1}&7 of &f{2}&7 - &f{3}&7 entries)"
listnodes-temp-with-page: "&b{0}'s Temporary Permissions: {1}" parent-info-no-data: "&b{0}&a does not have any parents defined."
listparents: "&b{0}'s Parent Groups:" list-tracks: "&b{0}'s Tracks:"
listparents-temp: "&b{0}'s Temporary Parent Groups:" list-tracks-entry: "&a{0}: {1}"
list-tracks: >
&b{0}'s Tracks:\n
{1}
list-tracks-empty: "&b{0}&a is not on any tracks." list-tracks-empty: "&b{0}&a is not on any tracks."
context-pair-inline: "&3{0}=&b{1}" context-pair-inline: "&3{0}=&b{1}"
context-pair--global-inline: "&eglobal" context-pair--global-inline: "&eglobal"
@ -413,6 +410,10 @@ command-specs:
args: args:
"track": "the track to demote the user down" "track": "the track to demote the user down"
"context...": "the contexts to demote the user in" "context...": "the contexts to demote the user in"
user-clone:
description: "Clone the user"
args:
"user": "the name/uuid of the user to clone onto"
group-info: group-info:
description: "Gives info about the group" description: "Gives info about the group"
group-listmembers: group-listmembers:
@ -423,6 +424,10 @@ command-specs:
description: "Set the groups weight" description: "Set the groups weight"
args: args:
"weight": "the weight to set" "weight": "the weight to set"
group-set-display-name:
description: "Set the groups display name"
args:
"name": "the name to set"
group-rename: group-rename:
description: "Rename the group" description: "Rename the group"
args: args:
@ -449,7 +454,7 @@ command-specs:
description: "Lists the permission nodes the object has" description: "Lists the permission nodes the object has"
args: args:
"page": "the page to view" "page": "the page to view"
"filter": "the string to filter by" "sort mode": "how to sort the entries"
permission-set: permission-set:
description: "Sets a permission for the object" description: "Sets a permission for the object"
args: args:
@ -485,6 +490,9 @@ command-specs:
"context...": "the contexts to check in" "context...": "the contexts to check in"
parent-info: parent-info:
description: "Lists the groups that this object inherits from" description: "Lists the groups that this object inherits from"
args:
"page": "the page to view"
"sort mode": "how to sort the entries"
parent-set: parent-set:
description: "Removes all other groups the object inherits already and adds them to the one given" description: "Removes all other groups the object inherits already and adds them to the one given"
args: args:

View File

@ -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"; private static final String FORMAT = "&8(&e%s&8) [&a%s&8] (&b%s&8) &7--> &f%s";
/** private static final Comparator<LogEntry> COMPARATOR = Comparator
* Compares two LogEntries
*
* @since 3.3
*/
public static final Comparator<LogEntry> COMPARATOR = Comparator
.comparingLong(LogEntry::getTimestamp) .comparingLong(LogEntry::getTimestamp)
.thenComparing(LogEntry::getActor) .thenComparing(LogEntry::getActor)
.thenComparing(LogEntry::getActorName, String.CASE_INSENSITIVE_ORDER) .thenComparing(LogEntry::getActorName, String.CASE_INSENSITIVE_ORDER)

View File

@ -54,6 +54,7 @@ import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors;
@AllArgsConstructor @AllArgsConstructor
public class ApiPermissionHolder implements PermissionHolder { public class ApiPermissionHolder implements PermissionHolder {
@ -179,7 +180,7 @@ public class ApiPermissionHolder implements PermissionHolder {
} }
@Override @Override
public void clearMatching(Predicate<Node> test) { public void clearMatching(@NonNull Predicate<Node> test) {
handle.removeIf(test); handle.removeIf(test);
if (handle.getType().isUser()) { if (handle.getType().isUser()) {
handle.getPlugin().getUserManager().giveDefaultIfNeeded((User) handle, false); handle.getPlugin().getUserManager().giveDefaultIfNeeded((User) handle, false);
@ -187,7 +188,7 @@ public class ApiPermissionHolder implements PermissionHolder {
} }
@Override @Override
public void clearMatchingTransient(Predicate<Node> test) { public void clearMatchingTransient(@NonNull Predicate<Node> test) {
handle.removeIfTransient(test); handle.removeIfTransient(test);
} }
@ -226,11 +227,6 @@ public class ApiPermissionHolder implements PermissionHolder {
handle.clearTransientNodes(); handle.clearTransientNodes();
} }
@Override
public Set<Node> getTemporaryPermissionNodes() {
return handle.getTemporaryNodes();
}
@Override @Override
public List<LocalizedNode> resolveInheritances(Contexts contexts) { public List<LocalizedNode> resolveInheritances(Contexts contexts) {
return handle.resolveInheritances(contexts); return handle.resolveInheritances(contexts);
@ -243,7 +239,12 @@ public class ApiPermissionHolder implements PermissionHolder {
@Override @Override
public Set<Node> getPermanentPermissionNodes() { 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 @Override

View File

@ -33,6 +33,7 @@ import com.google.common.base.Preconditions;
import me.lucko.luckperms.api.DataMutateResult; import me.lucko.luckperms.api.DataMutateResult;
import me.lucko.luckperms.api.User; import me.lucko.luckperms.api.User;
import me.lucko.luckperms.api.caching.UserData; import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.common.node.NodeFactory;
import java.util.UUID; import java.util.UUID;
@ -71,7 +72,7 @@ public final class ApiUser extends ApiPermissionHolder implements User {
return DataMutateResult.ALREADY_HAS; return DataMutateResult.ALREADY_HAS;
} }
if (!handle.hasPermission("group." + s.toLowerCase(), true)) { if (!handle.hasPermission(NodeFactory.make("group." + s.toLowerCase(), true)).asBoolean()) {
return DataMutateResult.FAIL; return DataMutateResult.FAIL;
} }

View File

@ -41,6 +41,7 @@ import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message; import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder; 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.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
@ -84,7 +85,7 @@ public class ParentAdd extends SharedSubCommand {
return CommandResult.NO_PERMISSION; 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()) { if (result.asBoolean()) {
Message.SET_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getFriendlyName(), CommandUtils.contextSetToString(context)); Message.SET_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getFriendlyName(), CommandUtils.contextSetToString(context));

View File

@ -41,6 +41,7 @@ import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User; 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.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
@ -85,7 +86,7 @@ public class ParentSet extends SharedSubCommand {
} }
holder.clearParents(context, false); holder.clearParents(context, false);
holder.setInheritGroup(group, context); holder.setPermission(NodeFactory.newBuilder("group." + group.getName()).withExtraContext(context).build());
if (holder.getType().isUser()) { if (holder.getType().isUser()) {
((User) holder).getPrimaryGroup().setStoredValue(group.getName()); ((User) holder).getPrimaryGroup().setStoredValue(group.getName());
} }

View File

@ -42,6 +42,7 @@ import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.Track; 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.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates; 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.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)); Message.SET_TRACK_PARENT_SUCCESS.send(sender, holder.getFriendlyName(), track.getName(), group.getFriendlyName(), CommandUtils.contextSetToString(context));

View File

@ -78,8 +78,8 @@ public class GroupClone extends SubCommand<Group> {
Message.CLONE_SUCCESS.send(sender, group.getName(), newGroup.getName()); Message.CLONE_SUCCESS.send(sender, group.getName(), newGroup.getName());
ExtendedLogEntry.build().actor(sender).acted(group) ExtendedLogEntry.build().actor(sender).acted(newGroup)
.action("clone", newGroup.getName()) .action("clone", group.getName())
.build().submit(plugin, sender); .build().submit(plugin, sender);
save(newGroup, sender, plugin); save(newGroup, sender, plugin);

View File

@ -63,9 +63,9 @@ public class GroupInfo extends SubCommand<Group> {
group.getWeight().isPresent() ? group.getWeight().getAsInt() : "None", group.getWeight().isPresent() ? group.getWeight().getAsInt() : "None",
group.getOwnNodes().size(), group.getOwnNodes().size(),
group.getOwnNodes().stream().filter(n -> !(n.isGroupNode() || n.isPrefix() || n.isSuffix() || n.isMeta())).mapToInt(n -> 1).sum(), group.getOwnNodes().stream().filter(n -> !(n.isGroupNode() || n.isPrefix() || n.isSuffix() || n.isMeta())).mapToInt(n -> 1).sum(),
group.getPrefixNodes().size(), group.getOwnNodes().stream().filter(Node::isPrefix).mapToInt(n -> 1).sum(),
group.getSuffixNodes().size(), group.getOwnNodes().stream().filter(Node::isSuffix).mapToInt(n -> 1).sum(),
group.getMetaNodes().size() group.getOwnNodes().stream().filter(Node::isMeta).mapToInt(n -> 1).sum()
); );
Set<Node> parents = group.getOwnNodesSet().stream() Set<Node> parents = group.getOwnNodesSet().stream()

View File

@ -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;
}
}

View File

@ -67,9 +67,9 @@ public class UserInfo extends SubCommand<User> {
user.getPrimaryGroup().getValue(), user.getPrimaryGroup().getValue(),
user.getOwnNodes().size(), user.getOwnNodes().size(),
user.getOwnNodes().stream().filter(n -> !(n.isGroupNode() || n.isPrefix() || n.isSuffix() || n.isMeta())).mapToInt(n -> 1).sum(), user.getOwnNodes().stream().filter(n -> !(n.isGroupNode() || n.isPrefix() || n.isSuffix() || n.isMeta())).mapToInt(n -> 1).sum(),
user.getPrefixNodes().size(), user.getOwnNodes().stream().filter(Node::isPrefix).mapToInt(n -> 1).sum(),
user.getSuffixNodes().size(), user.getOwnNodes().stream().filter(Node::isSuffix).mapToInt(n -> 1).sum(),
user.getMetaNodes().size() user.getOwnNodes().stream().filter(Node::isMeta).mapToInt(n -> 1).sum()
); );
Set<Node> parents = user.getOwnNodesSet().stream() Set<Node> parents = user.getOwnNodesSet().stream()

View File

@ -76,6 +76,7 @@ public class UserMainCommand extends MainCommand<User, UserIdentifier> {
.add(new UserDemote(locale)) .add(new UserDemote(locale))
.add(new HolderShowTracks<>(locale, true)) .add(new HolderShowTracks<>(locale, true))
.add(new HolderClear<>(locale, true)) .add(new HolderClear<>(locale, true))
.add(new UserClone(locale))
.build() .build()
); );
} }

View File

@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.impl.user; 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.actionlog.ExtendedLogEntry;
import me.lucko.luckperms.common.commands.ArgumentPermissions; import me.lucko.luckperms.common.commands.ArgumentPermissions;
import me.lucko.luckperms.common.commands.CommandException; 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.locale.Message;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.User; 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.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
@ -74,7 +74,7 @@ public class UserSwitchPrimaryGroup extends SubCommand<User> {
if (!user.inheritsGroup(group)) { if (!user.inheritsGroup(group)) {
Message.USER_PRIMARYGROUP_ERROR_NOTMEMBER.send(sender, user.getFriendlyName(), group.getName()); 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()); user.getPrimaryGroup().setStoredValue(group.getName());

View File

@ -100,6 +100,7 @@ public enum CommandPermission {
USER_PROMOTE("promote", USER), USER_PROMOTE("promote", USER),
USER_DEMOTE("demote", USER), USER_DEMOTE("demote", USER),
USER_CLEAR("clear", USER), USER_CLEAR("clear", USER),
USER_CLONE("clone", USER),
GROUP_INFO("info", GROUP), GROUP_INFO("info", GROUP),
GROUP_PERM_INFO("permission.info", GROUP), GROUP_PERM_INFO("permission.info", GROUP),

View File

@ -148,6 +148,11 @@ public enum CommandSpec {
Arg.create("context...", false, "the contexts to demote the user in") 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_INFO("Gives info about the group"),
GROUP_LISTMEMBERS("Show the users/groups who inherit from this group", GROUP_LISTMEMBERS("Show the users/groups who inherit from this group",

View File

@ -152,6 +152,7 @@ public enum Message {
ALREADY_EXISTS("&4{}&c already exists!", true), ALREADY_EXISTS("&4{}&c already exists!", true),
DOES_NOT_EXIST("&4{}&c does not exist!", 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), GROUP_LOAD_ERROR("&cAn unexpected error occurred. Group not loaded.", true),
GROUPS_LOAD_ERROR("&cAn unexpected error occurred. Unable to load all groups.", true), GROUPS_LOAD_ERROR("&cAn unexpected error occurred. Unable to load all groups.", true),

View File

@ -975,30 +975,6 @@ public abstract class PermissionHolder {
return hasPermission(node, false); 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 * Check if the holder inherits a node
* *
@ -1025,30 +1001,6 @@ public abstract class PermissionHolder {
return inheritsPermissionInfo(node).getResult(); 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 * Sets a permission node
* *
@ -1201,33 +1153,6 @@ public abstract class PermissionHolder {
return DataMutateResult.SUCCESS; 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 * Unsets a transient permission node
* *
@ -1255,29 +1180,13 @@ public abstract class PermissionHolder {
} }
public boolean inheritsGroup(Group group) { 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) { public boolean inheritsGroup(Group group, ContextSet contextSet) {
return group.getName().equalsIgnoreCase(this.getObjectName()) || hasPermission(NodeFactory.newBuilder("group." + group.getName()).withExtraContext(contextSet).build()).asBoolean(); 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 * Clear all of the holders permission nodes
*/ */
@ -1478,32 +1387,6 @@ public abstract class PermissionHolder {
return true; 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() { public OptionalInt getWeight() {
return weightCache.get(); return weightCache.get();
} }