Add configurable duration handling when a holder already has a temporary permission/parent/option set - closes #152

This commit is contained in:
Luck 2017-02-03 22:24:42 +00:00
parent 1d71ec07be
commit 6540c695de
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
11 changed files with 199 additions and 22 deletions

View File

@ -46,6 +46,14 @@ online-mode: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
# Controls how temporary permissions/parents/meta should be accumulated
#
# The default behaviour is "deny"
# If "accumulate": durations will be added to the existing expiry time
# If "replace": durations will be replaced if the new duration is later than the current expiration
# If "deny": the command will just fail if you try to add another node with the same expiry
temporary-add-behaviour: deny

View File

@ -56,6 +56,14 @@ world-rewrite:
group-name-rewrite:
# default: Member
# Controls how temporary permissions/parents/meta should be accumulated
#
# The default behaviour is "deny"
# If "accumulate": durations will be added to the existing expiry time
# If "replace": durations will be replaced if the new duration is later than the current expiration
# If "deny": the command will just fail if you try to add another node with the same expiry
temporary-add-behaviour: deny

View File

@ -30,8 +30,11 @@ import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.TemporaryModifier;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@ -63,25 +66,26 @@ public class MetaAddTempPrefix extends SharedSubCommand {
long duration = ArgumentUtils.handleDuration(2, args);
String server = ArgumentUtils.handleServer(3, args);
String world = ArgumentUtils.handleWorld(4, args);
TemporaryModifier modifier = plugin.getConfiguration().get(ConfigKeys.TEMPORARY_ADD_BEHAVIOUR);
final String node = "prefix." + priority + "." + MetaUtils.escapeCharacters(prefix);
try {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setPermission(node, true, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(true).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.ADD_TEMP_PREFIX_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority,
DateUtil.formatDateDiff(duration)
);
break;
case SERVER:
holder.setPermission(node, true, server, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(true).setServer(server).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.ADD_TEMP_PREFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority,
server, DateUtil.formatDateDiff(duration)
);
break;
case SERVER_AND_WORLD:
holder.setPermission(node, true, server, world, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(true).setServer(server).setWorld(world).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.ADD_TEMP_PREFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), prefix, priority,
server, world, DateUtil.formatDateDiff(duration)
);

View File

@ -30,8 +30,11 @@ import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.TemporaryModifier;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@ -63,25 +66,26 @@ public class MetaAddTempSuffix extends SharedSubCommand {
long duration = ArgumentUtils.handleDuration(2, args);
String server = ArgumentUtils.handleServer(3, args);
String world = ArgumentUtils.handleWorld(4, args);
TemporaryModifier modifier = plugin.getConfiguration().get(ConfigKeys.TEMPORARY_ADD_BEHAVIOUR);
final String node = "suffix." + priority + "." + MetaUtils.escapeCharacters(suffix);
try {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setPermission(node, true, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(true).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.ADD_TEMP_SUFFIX_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority,
DateUtil.formatDateDiff(duration)
);
break;
case SERVER:
holder.setPermission(node, true, server, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(true).setServer(server).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.ADD_TEMP_SUFFIX_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority,
server, DateUtil.formatDateDiff(duration)
);
break;
case SERVER_AND_WORLD:
holder.setPermission(node, true, server, world, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(true).setServer(server).setWorld(world).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.ADD_TEMP_SUFFIX_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), suffix, priority,
server, world, DateUtil.formatDateDiff(duration)
);

View File

@ -30,9 +30,11 @@ import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.TemporaryModifier;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@ -63,6 +65,7 @@ public class MetaSetTemp extends SharedSubCommand {
long duration = ArgumentUtils.handleDuration(2, args);
String server = ArgumentUtils.handleServer(3, args);
String world = ArgumentUtils.handleWorld(4, args);
TemporaryModifier modifier = plugin.getConfiguration().get(ConfigKeys.TEMPORARY_ADD_BEHAVIOUR);
Node n = NodeFactory.makeMetaNode(key, value).setServer(server).setWorld(world).setExpiry(duration).build();
@ -74,9 +77,8 @@ public class MetaSetTemp extends SharedSubCommand {
holder.clearMetaKeys(key, server, world, true);
try {
holder.setPermission(n);
} catch (ObjectAlreadyHasException ignored) {
}
duration = holder.setPermission(n, modifier).getExpiryUnixTime();
} catch (ObjectAlreadyHasException ignored) {}
switch (ContextHelper.determine(server, world)) {
case NONE:

View File

@ -22,6 +22,9 @@
package me.lucko.luckperms.common.commands.generic.parent;
import me.lucko.luckperms.api.event.events.GroupAddEvent;
import me.lucko.luckperms.common.api.delegate.GroupDelegate;
import me.lucko.luckperms.common.api.delegate.PermissionHolderDelegate;
import me.lucko.luckperms.common.commands.Arg;
import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult;
@ -29,8 +32,11 @@ import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.TemporaryModifier;
import me.lucko.luckperms.common.core.model.Group;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
@ -63,6 +69,7 @@ public class ParentAddTemp extends SharedSubCommand {
long duration = ArgumentUtils.handleDuration(1, args);
String server = ArgumentUtils.handleServer(2, args);
String world = ArgumentUtils.handleWorld(3, args);
TemporaryModifier modifier = plugin.getConfiguration().get(ConfigKeys.TEMPORARY_ADD_BEHAVIOUR);
if (!plugin.getStorage().loadGroup(groupName).join()) {
Message.GROUP_DOES_NOT_EXIST.send(sender);
@ -76,24 +83,31 @@ public class ParentAddTemp extends SharedSubCommand {
}
try {
if (group.getName().equalsIgnoreCase(holder.getObjectName())) {
throw new ObjectAlreadyHasException();
}
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setInheritGroup(group, duration);
duration = holder.setPermission(new NodeBuilder("group." + group.getName()).setValue(true).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.SET_TEMP_INHERIT_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName(),
DateUtil.formatDateDiff(duration)
);
plugin.getApiProvider().fireEventAsync(new GroupAddEvent(new PermissionHolderDelegate(holder), new GroupDelegate(group), null, null, duration));
break;
case SERVER:
holder.setInheritGroup(group, server, duration);
duration = holder.setPermission(new NodeBuilder("group." + group.getName()).setValue(true).setServer(server).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.SET_TEMP_INHERIT_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName(),
server, DateUtil.formatDateDiff(duration)
);
plugin.getApiProvider().fireEventAsync(new GroupAddEvent(new PermissionHolderDelegate(holder), new GroupDelegate(group), server, null, duration));
break;
case SERVER_AND_WORLD:
holder.setInheritGroup(group, server, world, duration);
duration = holder.setPermission(new NodeBuilder("group." + group.getName()).setValue(true).setServer(server).setWorld(world).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.SET_TEMP_INHERIT_SERVER_WORLD_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName(),
server, world, DateUtil.formatDateDiff(duration)
);
plugin.getApiProvider().fireEventAsync(new GroupAddEvent(new PermissionHolderDelegate(holder), new GroupDelegate(group), server, world, duration));
break;
}

View File

@ -29,8 +29,11 @@ import me.lucko.luckperms.common.commands.generic.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.ContextHelper;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.constants.Message;
import me.lucko.luckperms.common.constants.Permission;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.TemporaryModifier;
import me.lucko.luckperms.common.core.model.PermissionHolder;
import me.lucko.luckperms.common.data.LogEntry;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@ -68,22 +71,24 @@ public class PermissionSetTemp extends SharedSubCommand {
String server = ArgumentUtils.handleServer(3, args);
String world = ArgumentUtils.handleWorld(4, args);
TemporaryModifier modifier = plugin.getConfiguration().get(ConfigKeys.TEMPORARY_ADD_BEHAVIOUR);
try {
switch (ContextHelper.determine(server, world)) {
case NONE:
holder.setPermission(node, b, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(b).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.SETPERMISSION_TEMP_SUCCESS.send(sender, node, b, holder.getFriendlyName(),
DateUtil.formatDateDiff(duration)
);
break;
case SERVER:
holder.setPermission(node, b, server, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(b).setServer(server).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.SETPERMISSION_TEMP_SERVER_SUCCESS.send(sender, node, b, holder.getFriendlyName(), server,
DateUtil.formatDateDiff(duration)
);
break;
case SERVER_AND_WORLD:
holder.setPermission(node, b, server, world, duration);
duration = holder.setPermission(new NodeBuilder(node).setValue(b).setServer(server).setWorld(world).setExpiry(duration).build(), modifier).getExpiryUnixTime();
Message.SETPERMISSION_TEMP_SERVER_WORLD_SUCCESS.send(sender, node, b, holder.getFriendlyName(),
server, world, DateUtil.formatDateDiff(duration)
);

View File

@ -36,6 +36,7 @@ import me.lucko.luckperms.common.config.keys.IntegerKey;
import me.lucko.luckperms.common.config.keys.MapKey;
import me.lucko.luckperms.common.config.keys.StaticKey;
import me.lucko.luckperms.common.config.keys.StringKey;
import me.lucko.luckperms.common.core.TemporaryModifier;
import me.lucko.luckperms.common.defaults.Rule;
import me.lucko.luckperms.common.storage.DatastoreConfiguration;
import me.lucko.luckperms.common.utils.ImmutableCollectors;
@ -58,6 +59,14 @@ public class ConfigKeys {
public static final ConfigKey<Boolean> APPLYING_GLOBAL_GROUPS = BooleanKey.of("apply-global-groups", true);
public static final ConfigKey<Boolean> APPLYING_GLOBAL_WORLD_GROUPS = BooleanKey.of("apply-global-world-groups", true);
public static final ConfigKey<Boolean> ONLINE_MODE = BooleanKey.of("online-mode", true);
public static final ConfigKey<TemporaryModifier> TEMPORARY_ADD_BEHAVIOUR = AbstractKey.of(c -> {
String option = c.getString("temporary-add-behaviour", "deny").toLowerCase();
if (!option.equals("deny") && !option.equals("replace") && !option.equals("accumulate")) {
option = "deny";
}
return TemporaryModifier.valueOf(option.toUpperCase());
});
public static final ConfigKey<Boolean> APPLYING_WILDCARDS = EnduringKey.wrap(BooleanKey.of("apply-wildcards", true));
public static final ConfigKey<Boolean> APPLYING_REGEX = EnduringKey.wrap(BooleanKey.of("apply-regex", true));
public static final ConfigKey<Boolean> APPLYING_SHORTHAND = EnduringKey.wrap(BooleanKey.of("apply-shorthand", true));

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2016 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.core;
/**
* Controls how temporary permissions/parents/meta should be set
*/
public enum TemporaryModifier {
/**
* Durations will be added to the existing expiry time of a permission
*/
ACCUMULATE,
/**
* Durations will be replaced if the new duration is later than the current expiration
*/
REPLACE,
/**
* The command will just fail if you try to add another permission with the same expiry
*/
DENY
}

View File

@ -58,6 +58,7 @@ import me.lucko.luckperms.common.core.InheritanceInfo;
import me.lucko.luckperms.common.core.NodeBuilder;
import me.lucko.luckperms.common.core.NodeFactory;
import me.lucko.luckperms.common.core.PriorityComparator;
import me.lucko.luckperms.common.core.TemporaryModifier;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Cache;
import me.lucko.luckperms.common.utils.ExtractedContexts;
@ -593,6 +594,16 @@ public abstract class PermissionHolder {
return true;
}
public Optional<Node> getAlmostEquals(Node node, boolean t) {
for (Node n : t ? getTransientNodes() : getNodes()) {
if (n.almostEquals(node)) {
return Optional.of(n);
}
}
return Optional.empty();
}
/**
* Check if the holder has a permission node
*
@ -601,13 +612,7 @@ public abstract class PermissionHolder {
* @return a tristate
*/
public Tristate hasPermission(Node node, boolean t) {
for (Node n : t ? getTransientNodes() : getNodes()) {
if (n.almostEquals(node)) {
return n.getTristate();
}
}
return Tristate.UNDEFINED;
return getAlmostEquals(node, t).map(Node::getTristate).orElse(Tristate.UNDEFINED);
}
public Tristate hasPermission(Node node) {
@ -707,6 +712,71 @@ public abstract class PermissionHolder {
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderDelegate(this), node));
}
/**
* Sets a permission node, applying a temporary modifier if the node is temporary.
* @param node the node to set
* @param modifier the modifier to use for the operation
* @return the node that was actually set, respective of the modifier
* @throws ObjectAlreadyHasException if the holder has this permission set already, respective of the modifier
*/
public Node setPermission(Node node, TemporaryModifier modifier) throws ObjectAlreadyHasException {
// If the node is temporary, we should take note of the modifier
if (node.isTemporary()) {
if (modifier == TemporaryModifier.ACCUMULATE) {
// Try to accumulate with an existing node
Optional<Node> existing = getAlmostEquals(node, false);
// An existing node was found
if (existing.isPresent()) {
Node previous = existing.get();
// Create a new node with the same properties, but add the expiry dates together
Node newNode = NodeFactory.builderFromExisting(node).setExpiry(previous.getExpiryUnixTime() + node.getSecondsTilExpiry()).build();
// Remove the old node & add the new one.
synchronized (nodes) {
nodes.remove(previous);
nodes.add(newNode);
}
invalidateCache(true);
plugin.getApiProvider().fireEventAsync(new PermissionNodeUnsetEvent(new PermissionHolderDelegate(this), previous));
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderDelegate(this), newNode));
return newNode;
}
} else if (modifier == TemporaryModifier.REPLACE) {
// Try to replace an existing node
Optional<Node> existing = getAlmostEquals(node, false);
// An existing node was found
if (existing.isPresent()) {
Node previous = existing.get();
// Only replace if the new expiry time is greater than the old one.
if (node.getExpiryUnixTime() > previous.getExpiryUnixTime()) {
synchronized (nodes) {
nodes.remove(previous);
nodes.add(node);
}
invalidateCache(true);
plugin.getApiProvider().fireEventAsync(new PermissionNodeUnsetEvent(new PermissionHolderDelegate(this), previous));
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderDelegate(this), node));
return node;
}
}
}
// DENY behaviour is the default anyways.
}
// Fallback to the normal handling.
setPermission(node);
return node;
}
/**
* Sets a transient permission node
*

View File

@ -54,6 +54,14 @@ group-name-rewrite {
# default="Member"
}
# Controls how temporary permissions/parents/meta should be accumulated
#
# The default behaviour is "deny"
# If "accumulate": durations will be added to the existing expiry time
# If "replace": durations will be replaced if the new duration is later than the current expiration
# If "deny": the command will just fail if you try to add another node with the same expiry
temporary-add-behaviour="deny"