diff --git a/api/src/main/java/me/lucko/luckperms/api/Node.java b/api/src/main/java/me/lucko/luckperms/api/Node.java index 87f43e5a7..5da591ec7 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Node.java +++ b/api/src/main/java/me/lucko/luckperms/api/Node.java @@ -291,6 +291,14 @@ public interface Node { @Nonnull ContextSet getFullContexts(); + /** + * Returns if the node is a "standard" permission node. + * + * @return true if this is a regular permission node + * @since 4.2 + */ + boolean isRegularPermissionNode(); + /** * Returns if this is a group node. * diff --git a/common/src/main/java/me/lucko/luckperms/common/command/access/CommandPermission.java b/common/src/main/java/me/lucko/luckperms/common/command/access/CommandPermission.java index dde4025c5..530881faa 100644 --- a/common/src/main/java/me/lucko/luckperms/common/command/access/CommandPermission.java +++ b/common/src/main/java/me/lucko/luckperms/common/command/access/CommandPermission.java @@ -70,6 +70,7 @@ public enum CommandPermission { USER_PERM_UNSET_TEMP("permission.unsettemp", USER), USER_PERM_CHECK("permission.check", USER), USER_PERM_CHECK_INHERITS("permission.checkinherits", USER), + USER_PERM_CLEAR("permission.clear", USER), USER_PARENT_INFO("parent.info", USER), USER_PARENT_SET("parent.set", USER), USER_PARENT_SET_TRACK("parent.settrack", USER), @@ -109,6 +110,7 @@ public enum CommandPermission { GROUP_PERM_UNSET_TEMP("permission.unsettemp", GROUP), GROUP_PERM_CHECK("permission.check", GROUP), GROUP_PERM_CHECK_INHERITS("permission.checkinherits", GROUP), + GROUP_PERM_CLEAR("permission.clear", GROUP), GROUP_PARENT_INFO("parent.info", GROUP), GROUP_PARENT_SET("parent.set", GROUP), GROUP_PARENT_SET_TRACK("parent.settrack", GROUP), diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/CommandPermission.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/CommandPermission.java index 0b57d293c..d4b478c06 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/CommandPermission.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/CommandPermission.java @@ -43,6 +43,7 @@ public class CommandPermission extends SharedMainCom .add(new PermissionUnsetTemp(locale)) .add(new PermissionCheck(locale)) .add(new PermissionCheckInherits(locale)) + .add(new PermissionClear(locale)) .build()); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionClear.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionClear.java new file mode 100644 index 000000000..6d9c46c36 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/permission/PermissionClear.java @@ -0,0 +1,89 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.commands.generic.permission; + +import me.lucko.luckperms.api.context.MutableContextSet; +import me.lucko.luckperms.common.actionlog.ExtendedLogEntry; +import me.lucko.luckperms.common.command.CommandResult; +import me.lucko.luckperms.common.command.abstraction.CommandException; +import me.lucko.luckperms.common.command.abstraction.SharedSubCommand; +import me.lucko.luckperms.common.command.access.ArgumentPermissions; +import me.lucko.luckperms.common.command.access.CommandPermission; +import me.lucko.luckperms.common.command.utils.ArgumentParser; +import me.lucko.luckperms.common.command.utils.MessageUtils; +import me.lucko.luckperms.common.command.utils.StorageAssistant; +import me.lucko.luckperms.common.locale.LocaleManager; +import me.lucko.luckperms.common.locale.command.CommandSpec; +import me.lucko.luckperms.common.locale.message.Message; +import me.lucko.luckperms.common.model.PermissionHolder; +import me.lucko.luckperms.common.plugin.LuckPermsPlugin; +import me.lucko.luckperms.common.sender.Sender; +import me.lucko.luckperms.common.utils.Predicates; + +import java.util.List; + +public class PermissionClear extends SharedSubCommand { + public PermissionClear(LocaleManager locale) { + super(CommandSpec.PERMISSION_CLEAR.localize(locale), "clear", CommandPermission.USER_PERM_CLEAR, CommandPermission.GROUP_PERM_CLEAR, Predicates.alwaysFalse()); + } + + @Override + public CommandResult execute(LuckPermsPlugin plugin, Sender sender, PermissionHolder holder, List args, String label, CommandPermission permission) throws CommandException { + if (ArgumentPermissions.checkModifyPerms(plugin, sender, permission, holder)) { + Message.COMMAND_NO_PERMISSION.send(sender); + return CommandResult.NO_PERMISSION; + } + + int before = holder.getEnduringNodes().size(); + + MutableContextSet context = ArgumentParser.parseContext(0, args, plugin); + + if (ArgumentPermissions.checkContext(plugin, sender, permission, context)) { + Message.COMMAND_NO_PERMISSION.send(sender); + return CommandResult.NO_PERMISSION; + } + + if (context.isEmpty()) { + holder.clearPermissions(); + } else { + holder.clearPermissions(context); + } + + int changed = before - holder.getEnduringNodes().size(); + if (changed == 1) { + Message.PERMISSION_CLEAR_SUCCESS_SINGULAR.send(sender, holder.getFriendlyName(), MessageUtils.contextSetToString(context), changed); + } else { + Message.PERMISSION_CLEAR_SUCCESS.send(sender, holder.getFriendlyName(), MessageUtils.contextSetToString(context), changed); + } + + ExtendedLogEntry.build().actor(sender).acted(holder) + .action("permission", "clear", context) + .build().submit(plugin, sender); + + StorageAssistant.save(holder, sender, plugin); + return CommandResult.SUCCESS; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/locale/command/CommandSpec.java b/common/src/main/java/me/lucko/luckperms/common/locale/command/CommandSpec.java index dfc5ae699..6e592381b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/locale/command/CommandSpec.java +++ b/common/src/main/java/me/lucko/luckperms/common/locale/command/CommandSpec.java @@ -240,6 +240,11 @@ public enum CommandSpec { Argument.create("context...", false, "the contexts to check in") ) ), + PERMISSION_CLEAR("Clears all permissions", + Argument.list( + Argument.create("context...", false, "the contexts to filter by") + ) + ), PARENT_INFO("Lists the groups that this object inherits from", Argument.list( diff --git a/common/src/main/java/me/lucko/luckperms/common/locale/message/Message.java b/common/src/main/java/me/lucko/luckperms/common/locale/message/Message.java index 219f4fc0a..cbee35478 100644 --- a/common/src/main/java/me/lucko/luckperms/common/locale/message/Message.java +++ b/common/src/main/java/me/lucko/luckperms/common/locale/message/Message.java @@ -245,8 +245,10 @@ public enum Message { UNSET_INHERIT_SUCCESS("&b{}&a no longer inherits permissions from &b{}&a in context {}&a.", true), UNSET_TEMP_INHERIT_SUCCESS("&b{}&a no longer temporarily inherits permissions from &b{}&a in context {}&a.", true), - CLEAR_SUCCESS("&b{}&a's permissions were cleared in context {}&a. (&b{}&a nodes were removed.)", true), - CLEAR_SUCCESS_SINGULAR("&b{}&a's permissions were cleared in context {}&a. (&b{}&a node was removed.)", true), + CLEAR_SUCCESS("&b{}&a's nodes were cleared in context {}&a. (&b{}&a nodes were removed.)", true), + CLEAR_SUCCESS_SINGULAR("&b{}&a's nodes were cleared in context {}&a. (&b{}&a node was removed.)", true), + PERMISSION_CLEAR_SUCCESS("&b{}&a's permissions were cleared in context {}&a. (&b{}&a nodes were removed.)", true), + PERMISSION_CLEAR_SUCCESS_SINGULAR("&b{}&a's permissions were cleared in context {}&a. (&b{}&a node was removed.)", true), PARENT_CLEAR_SUCCESS("&b{}&a's parents were cleared in context {}&a. (&b{}&a nodes were removed.)", true), PARENT_CLEAR_SUCCESS_SINGULAR("&b{}&a's parents were cleared in context {}&a. (&b{}&a node was removed.)", true), diff --git a/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java b/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java index 970af414c..f5e79f1c1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java @@ -330,10 +330,36 @@ public abstract class PermissionHolder { } public boolean removeIf(Predicate predicate) { + return removeIf(predicate, null); + } + + public boolean removeIf(Predicate predicate, Runnable taskIfSuccess) { ImmutableCollection before = getEnduringNodes().values(); if (!this.enduringNodes.removeIf(predicate)) { return false; } + if (taskIfSuccess != null) { + taskIfSuccess.run(); + } + invalidateCache(); + ImmutableCollection after = getEnduringNodes().values(); + + this.plugin.getEventFactory().handleNodeClear(this, before, after); + return true; + } + + public boolean removeIf(ContextSet contextSet, Predicate predicate) { + return removeIf(contextSet, predicate, null); + } + + public boolean removeIf(ContextSet contextSet, Predicate predicate, Runnable taskIfSuccess) { + ImmutableCollection before = getEnduringNodes().values(); + if (!this.enduringNodes.removeIf(contextSet, predicate)) { + return false; + } + if (taskIfSuccess != null) { + taskIfSuccess.run(); + } invalidateCache(); ImmutableCollection after = getEnduringNodes().values(); @@ -820,86 +846,44 @@ public abstract class PermissionHolder { return true; } + public boolean clearPermissions() { + return removeIf(Node::isRegularPermissionNode); + } + + public boolean clearPermissions(ContextSet contextSet) { + return removeIf(contextSet, Node::isRegularPermissionNode); + } + public boolean clearParents(boolean giveDefault) { - ImmutableCollection before = getEnduringNodes().values(); - - if (!this.enduringNodes.removeIf(Node::isGroupNode)) { - return false; - } - if (this.getType().isUser() && giveDefault) { - this.plugin.getUserManager().giveDefaultIfNeeded((User) this, false); - } - - invalidateCache(); - ImmutableCollection after = getEnduringNodes().values(); - - this.plugin.getEventFactory().handleNodeClear(this, before, after); - return true; + return removeIf(Node::isGroupNode, () -> { + if (this.getType().isUser() && giveDefault) { + this.plugin.getUserManager().giveDefaultIfNeeded((User) this, false); + } + }); } public boolean clearParents(ContextSet contextSet, boolean giveDefault) { - ImmutableCollection before = getEnduringNodes().values(); - - if (!this.enduringNodes.removeIf(contextSet, Node::isGroupNode)) { - return false; - } - if (this.getType().isUser() && giveDefault) { - this.plugin.getUserManager().giveDefaultIfNeeded((User) this, false); - } - - invalidateCache(); - ImmutableCollection after = getEnduringNodes().values(); - - this.plugin.getEventFactory().handleNodeClear(this, before, after); - return true; + return removeIf(contextSet, Node::isGroupNode, () -> { + if (this.getType().isUser() && giveDefault) { + this.plugin.getUserManager().giveDefaultIfNeeded((User) this, false); + } + }); } public boolean clearMeta(MetaType type) { - ImmutableCollection before = getEnduringNodes().values(); - if (!this.enduringNodes.removeIf(type::matches)) { - return false; - } - invalidateCache(); - ImmutableCollection after = getEnduringNodes().values(); - - this.plugin.getEventFactory().handleNodeClear(this, before, after); - return true; + return removeIf(type::matches); } public boolean clearMeta(MetaType type, ContextSet contextSet) { - ImmutableCollection before = getEnduringNodes().values(); - if (!this.enduringNodes.removeIf(contextSet, type::matches)) { - return false; - } - invalidateCache(); - ImmutableCollection after = getEnduringNodes().values(); - - this.plugin.getEventFactory().handleNodeClear(this, before, after); - return true; + return removeIf(contextSet, type::matches); } public boolean clearMetaKeys(String key, boolean temp) { - ImmutableCollection before = getEnduringNodes().values(); - if (!this.enduringNodes.removeIf(n -> n.isMeta() && (n.isTemporary() == temp) && n.getMeta().getKey().equalsIgnoreCase(key))) { - return false; - } - invalidateCache(); - ImmutableCollection after = getEnduringNodes().values(); - - this.plugin.getEventFactory().handleNodeClear(this, before, after); - return true; + return removeIf(n -> n.isMeta() && (n.isTemporary() == temp) && n.getMeta().getKey().equalsIgnoreCase(key)); } public boolean clearMetaKeys(String key, ContextSet contextSet, boolean temp) { - ImmutableCollection before = getEnduringNodes().values(); - if (!this.enduringNodes.removeIf(contextSet, n -> n.isMeta() && (n.isTemporary() == temp) && n.getMeta().getKey().equalsIgnoreCase(key))) { - return false; - } - invalidateCache(); - ImmutableCollection after = getEnduringNodes().values(); - - this.plugin.getEventFactory().handleNodeClear(this, before, after); - return true; + return removeIf(contextSet, n -> n.isMeta() && (n.isTemporary() == temp) && n.getMeta().getKey().equalsIgnoreCase(key)); } public boolean clearTransientNodes() { diff --git a/common/src/main/java/me/lucko/luckperms/common/node/ForwardingNode.java b/common/src/main/java/me/lucko/luckperms/common/node/ForwardingNode.java index 3255899b9..a0dcc59d0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/ForwardingNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/ForwardingNode.java @@ -171,6 +171,11 @@ public abstract class ForwardingNode implements Node { return delegate().getFullContexts(); } + @Override + public boolean isRegularPermissionNode() { + return delegate().isRegularPermissionNode(); + } + @Override public boolean isGroupNode() { return delegate().isGroupNode(); diff --git a/common/src/main/java/me/lucko/luckperms/common/node/ImmutableNode.java b/common/src/main/java/me/lucko/luckperms/common/node/ImmutableNode.java index 34c0087c7..59288cad0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/ImmutableNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/ImmutableNode.java @@ -255,6 +255,11 @@ public final class ImmutableNode implements Node { return isTemporary() && this.expireAt < System.currentTimeMillis() / 1000L; } + @Override + public boolean isRegularPermissionNode() { + return !isGroupNode() && !isPrefix() && !isSuffix() && !isMeta(); + } + @Override public boolean isGroupNode() { return this.groupName != null;