More progress towards 1.6: implement PermissionService

This commit is contained in:
Luck
2016-08-28 14:57:03 +01:00
Unverified
parent 2a305b1c55
commit a3ebf86f6b
14 changed files with 1091 additions and 583 deletions
@@ -20,14 +20,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.service;
package me.lucko.luckperms.api.sponge;
import com.google.common.collect.ImmutableSet;
import lombok.*;
import me.lucko.luckperms.LPSpongePlugin;
import me.lucko.luckperms.service.collections.GroupCollection;
import me.lucko.luckperms.service.collections.UserCollection;
import me.lucko.luckperms.service.simple.SimpleCollection;
import me.lucko.luckperms.api.sponge.collections.GroupCollection;
import me.lucko.luckperms.api.sponge.collections.UserCollection;
import me.lucko.luckperms.api.sponge.simple.SimpleCollection;
import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.service.context.ContextCalculator;
import org.spongepowered.api.service.permission.*;
@@ -41,6 +41,7 @@ import java.util.stream.Collectors;
public class LuckPermsService implements PermissionService {
public static final String SERVER_CONTEXT = "server";
@Getter
private final LPSpongePlugin plugin;
@Getter
@@ -103,7 +104,7 @@ public class LuckPermsService implements PermissionService {
}
@Override
public Optional<PermissionDescription> getDescription(String s) {
public Optional<PermissionDescription> getDescription(@NonNull String s) {
for (PermissionDescription d : descriptionSet) {
if (d.getId().equals(s)) {
return Optional.of(d);
@@ -119,7 +120,7 @@ public class LuckPermsService implements PermissionService {
}
@Override
public void registerContextCalculator(ContextCalculator<Subject> contextCalculator) {
public void registerContextCalculator(@NonNull ContextCalculator<Subject> contextCalculator) {
contextCalculators.add(contextCalculator);
}
@@ -0,0 +1,837 @@
/*
* 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.api.sponge;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.data.Callback;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.users.User;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import java.util.*;
import java.util.stream.Collectors;
import static me.lucko.luckperms.utils.ArgumentChecker.escapeCharacters;
import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters;
@AllArgsConstructor
public class LuckPermsSubject implements Subject {
private final EnduringData enduringData;
private final TransientData transientData;
private final LuckPermsService service;
public LuckPermsSubject(PermissionHolder holder, LuckPermsService service) {
this.enduringData = new EnduringData(this, service, holder);
this.transientData = new TransientData(service, holder);
this.service = service;
}
private void objectSave(PermissionHolder t) {
if (t instanceof User) {
((User) t).refreshPermissions();
service.getPlugin().getDatastore().saveUser(((User) t), Callback.empty());
}
if (t instanceof Group) {
service.getPlugin().getDatastore().saveGroup(((Group) t), c -> service.getPlugin().runUpdateTask());
}
}
@Override
public String getIdentifier() {
return enduringData.getHolder().getObjectName();
}
@Override
public Optional<CommandSource> getCommandSource() {
if (enduringData.getHolder() instanceof User) {
final UUID uuid = ((User) enduringData.getHolder()).getUuid();
Optional<Player> p = Sponge.getServer().getPlayer(uuid);
if (p.isPresent()) {
return Optional.of(p.get());
}
}
return Optional.empty();
}
@Override
public SubjectCollection getContainingCollection() {
if (enduringData.getHolder() instanceof Group) {
return service.getGroupSubjects();
} else {
return service.getUserSubjects();
}
}
@Override
public SubjectData getSubjectData() {
return enduringData;
}
@Override
public SubjectData getTransientSubjectData() {
return transientData;
}
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return getPermissionValue(contexts, node).asBoolean();
}
@Override
public boolean hasPermission(String permission) {
return getPermissionValue(getActiveContexts(), permission).asBoolean();
}
@Override
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
Map<String, String> context = new HashMap<>();
for (Context c : contexts) {
context.put(c.getKey(), c.getValue());
}
me.lucko.luckperms.api.Tristate t = enduringData.getHolder().hasPermission(new me.lucko.luckperms.utils.Node.Builder(node).withExtraContext(context).build());
if (t == me.lucko.luckperms.api.Tristate.UNDEFINED) {
return Tristate.UNDEFINED;
}
if (t == me.lucko.luckperms.api.Tristate.TRUE) {
return Tristate.TRUE;
}
if (t == me.lucko.luckperms.api.Tristate.FALSE) {
return Tristate.FALSE;
}
return null;
}
@Override
public boolean isChildOf(@NonNull Subject parent) {
return isChildOf(getActiveContexts(), parent);
}
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
return parent instanceof PermissionHolder && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
}
@Override
public List<Subject> getParents() {
return getParents(getActiveContexts());
}
@Override
public List<Subject> getParents(@NonNull Set<Context> contexts) {
List<Subject> parents = new ArrayList<>();
parents.addAll(enduringData.getParents(contexts));
parents.addAll(transientData.getParents(contexts));
return ImmutableList.copyOf(parents);
}
@Override
public Optional<String> getOption(Set<Context> set, String s) {
Map<String, String> enduringOptions = enduringData.getOptions(set);
if (enduringOptions.containsKey(s)) {
return Optional.of(enduringOptions.get(s));
}
Map<String, String> transientOptions = enduringData.getOptions(set);
if (transientOptions.containsKey(s)) {
return Optional.of(transientOptions.get(s));
}
return Optional.empty();
}
@Override
public Optional<String> getOption(String key) {
return getOption(getActiveContexts(), key);
}
@Override
public Set<Context> getActiveContexts() {
return SubjectData.GLOBAL_CONTEXT;
}
@AllArgsConstructor
public static class EnduringData implements SubjectData {
private final LuckPermsSubject superClass;
private final LuckPermsService service;
@Getter
private final PermissionHolder holder;
@Override
public Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
Map<Set<Context>, Map<String, Boolean>> perms = new HashMap<>();
for (Node n : holder.getNodes()) {
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
.map(entry -> new Context(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
}
if (n.isWorldSpecific()) {
contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get()));
}
if (!perms.containsKey(contexts)) {
perms.put(contexts, new HashMap<>());
}
perms.get(contexts).put(n.getPermission(), n.getValue());
}
return ImmutableMap.copyOf(perms);
}
@Override
public Map<String, Boolean> getPermissions(Set<Context> set) {
return ImmutableMap.copyOf(getAllPermissions().getOrDefault(set, Collections.emptyMap()));
}
@Override
public boolean setPermission(Set<Context> set, String s, Tristate tristate) {
if (tristate == Tristate.UNDEFINED) {
// Unset
Node.Builder builder = new me.lucko.luckperms.utils.Node.Builder(s);
for (Context ct : set) {
builder.withExtraContext(ct.getKey(), ct.getValue());
}
try {
holder.unsetPermission(builder.build());
} catch (ObjectLacksException ignored) {}
superClass.objectSave(holder);
return true;
}
Node.Builder builder = new me.lucko.luckperms.utils.Node.Builder(s)
.setValue(tristate.asBoolean());
for (Context ct : set) {
builder.withExtraContext(ct.getKey(), ct.getValue());
}
try {
holder.setPermission(builder.build());
} catch (ObjectAlreadyHasException ignored) {}
superClass.objectSave(holder);
return true;
}
@Override
public boolean clearPermissions() {
// TODO re-give default nodes?
holder.getNodes().clear();
superClass.objectSave(holder);
return true;
}
@Override
public boolean clearPermissions(Set<Context> set) {
// TODO re-give default nodes?
Map<String, String> context = new HashMap<>();
for (Context c : set) {
context.put(c.getKey(), c.getValue());
}
boolean work = false;
Iterator<Node> iterator = holder.getNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (entry.shouldApplyWithContext(context)) {
iterator.remove();
work = true;
}
}
superClass.objectSave(holder);
return work;
}
@Override
public Map<Set<Context>, List<Subject>> getAllParents() {
Map<Set<Context>, List<Subject>> parents = new HashMap<>();
for (Node n : holder.getAllNodes(null)) {
if (!n.isGroupNode()) {
continue;
}
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
.map(entry -> new Context(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
}
if (n.isWorldSpecific()) {
contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get()));
}
if (!parents.containsKey(contexts)) {
parents.put(contexts, new ArrayList<>());
}
parents.get(contexts).add(service.getGroupSubjects().get(n.getGroupName()));
}
return ImmutableMap.copyOf(parents);
}
@Override
public List<Subject> getParents(Set<Context> contexts) {
return ImmutableList.copyOf(getAllParents().getOrDefault(contexts, Collections.emptyList()));
}
@Override
public boolean addParent(Set<Context> set, Subject subject) {
if (subject instanceof LuckPermsSubject) {
LuckPermsSubject permsSubject = ((LuckPermsSubject) subject);
Map<String, String> contexts = set.stream()
.map(context -> new AbstractMap.SimpleEntry<>(context.getKey(), context.getValue()))
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
try {
holder.setPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier())
.withExtraContext(contexts)
.build());
} catch (ObjectAlreadyHasException ignored) {}
superClass.objectSave(holder);
} else {
return false;
}
return false;
}
@Override
public boolean removeParent(Set<Context> set, Subject subject) {
if (subject instanceof LuckPermsSubject) {
LuckPermsSubject permsSubject = ((LuckPermsSubject) subject);
Map<String, String> contexts = set.stream()
.map(context -> new AbstractMap.SimpleEntry<>(context.getKey(), context.getValue()))
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
try {
holder.unsetPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier())
.withExtraContext(contexts)
.build());
} catch (ObjectLacksException ignored) {}
superClass.objectSave(holder);
} else {
return false;
}
return false;
}
@Override
public boolean clearParents() {
// TODO re-give default nodes?
boolean work = false;
Iterator<Node> iterator = holder.getNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (entry.isGroupNode()) {
iterator.remove();
work = true;
}
}
superClass.objectSave(holder);
return work;
}
@Override
public boolean clearParents(Set<Context> set) {
// TODO re-give default nodes?
Map<String, String> context = new HashMap<>();
for (Context c : set) {
context.put(c.getKey(), c.getValue());
}
boolean work = false;
Iterator<Node> iterator = holder.getNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (!entry.isGroupNode()) {
continue;
}
if (entry.shouldApplyWithContext(context)) {
iterator.remove();
work = true;
}
}
superClass.objectSave(holder);
return work;
}
@Override
public Map<Set<Context>, Map<String, String>> getAllOptions() {
Map<Set<Context>, Map<String, String>> options = new HashMap<>();
for (Node n : holder.getAllNodes(null)) {
if (!n.isMeta()) {
continue;
}
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
.map(entry -> new Context(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
}
if (n.isWorldSpecific()) {
contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get()));
}
if (!options.containsKey(contexts)) {
options.put(contexts, new HashMap<>());
}
options.get(contexts).put(unescapeCharacters(n.getMeta().getKey()), unescapeCharacters(n.getMeta().getValue()));
}
return ImmutableMap.copyOf(options);
}
@Override
public Map<String, String> getOptions(Set<Context> set) {
return ImmutableMap.copyOf(getAllOptions().getOrDefault(set, Collections.emptyMap()));
}
@Override
public boolean setOption(Set<Context> set, String key, String value) {
Map<String, String> context = new HashMap<>();
for (Context c : set) {
context.put(c.getKey(), c.getValue());
}
key = escapeCharacters(key);
value = escapeCharacters(value);
try {
holder.setPermission(new me.lucko.luckperms.utils.Node.Builder("meta." + key + "." + value)
.withExtraContext(context)
.build()
);
} catch (ObjectAlreadyHasException ignored) {}
superClass.objectSave(holder);
return true;
}
@Override
public boolean clearOptions(Set<Context> set) {
Map<String, String> context = new HashMap<>();
for (Context c : set) {
context.put(c.getKey(), c.getValue());
}
boolean work = false;
Iterator<Node> iterator = holder.getNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (!entry.isMeta()) {
continue;
}
if (entry.shouldApplyWithContext(context)) {
iterator.remove();
work = true;
}
}
superClass.objectSave(holder);
return work;
}
@Override
public boolean clearOptions() {
boolean work = false;
Iterator<Node> iterator = holder.getNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (entry.isMeta()) {
iterator.remove();
work = true;
}
}
superClass.objectSave(holder);
return work;
}
}
@AllArgsConstructor
public static class TransientData implements SubjectData {
private final LuckPermsService service;
@Getter
private final PermissionHolder holder;
@Override
public Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
Map<Set<Context>, Map<String, Boolean>> perms = new HashMap<>();
for (Node n : holder.getTransientNodes()) {
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
.map(entry -> new Context(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
}
if (n.isWorldSpecific()) {
contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get()));
}
if (!perms.containsKey(contexts)) {
perms.put(contexts, new HashMap<>());
}
perms.get(contexts).put(n.getPermission(), n.getValue());
}
return ImmutableMap.copyOf(perms);
}
@Override
public Map<String, Boolean> getPermissions(Set<Context> set) {
return ImmutableMap.copyOf(getAllPermissions().getOrDefault(set, Collections.emptyMap()));
}
@Override
public boolean setPermission(Set<Context> set, String s, Tristate tristate) {
if (tristate == Tristate.UNDEFINED) {
// Unset
Node.Builder builder = new me.lucko.luckperms.utils.Node.Builder(s);
for (Context ct : set) {
builder.withExtraContext(ct.getKey(), ct.getValue());
}
try {
holder.unsetTransientPermission(builder.build());
} catch (ObjectLacksException ignored) {}
return true;
}
Node.Builder builder = new me.lucko.luckperms.utils.Node.Builder(s)
.setValue(tristate.asBoolean());
for (Context ct : set) {
builder.withExtraContext(ct.getKey(), ct.getValue());
}
try {
holder.setTransientPermission(builder.build());
} catch (ObjectAlreadyHasException ignored) {}
return true;
}
@Override
public boolean clearPermissions() {
holder.getTransientNodes().clear();
return true;
}
@Override
public boolean clearPermissions(Set<Context> set) {
Map<String, String> context = new HashMap<>();
for (Context c : set) {
context.put(c.getKey(), c.getValue());
}
boolean work = false;
Iterator<Node> iterator = holder.getTransientNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (entry.shouldApplyWithContext(context)) {
iterator.remove();
work = true;
}
}
return work;
}
@Override
public Map<Set<Context>, List<Subject>> getAllParents() {
Map<Set<Context>, List<Subject>> parents = new HashMap<>();
for (Node n : holder.getTransientNodes()) {
if (!n.isGroupNode()) {
continue;
}
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
.map(entry -> new Context(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
}
if (n.isWorldSpecific()) {
contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get()));
}
if (!parents.containsKey(contexts)) {
parents.put(contexts, new ArrayList<>());
}
parents.get(contexts).add(service.getGroupSubjects().get(n.getGroupName()));
}
return ImmutableMap.copyOf(parents);
}
@Override
public List<Subject> getParents(Set<Context> contexts) {
return ImmutableList.copyOf(getAllParents().getOrDefault(contexts, Collections.emptyList()));
}
@Override
public boolean addParent(Set<Context> set, Subject subject) {
if (subject instanceof LuckPermsSubject) {
LuckPermsSubject permsSubject = ((LuckPermsSubject) subject);
Map<String, String> contexts = set.stream()
.map(context -> new AbstractMap.SimpleEntry<>(context.getKey(), context.getValue()))
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
try {
holder.setTransientPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier())
.withExtraContext(contexts)
.build());
} catch (ObjectAlreadyHasException ignored) {}
} else {
return false;
}
return false;
}
@Override
public boolean removeParent(Set<Context> set, Subject subject) {
if (subject instanceof LuckPermsSubject) {
LuckPermsSubject permsSubject = ((LuckPermsSubject) subject);
Map<String, String> contexts = set.stream()
.map(context -> new AbstractMap.SimpleEntry<>(context.getKey(), context.getValue()))
.collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
try {
holder.unsetTransientPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier())
.withExtraContext(contexts)
.build());
} catch (ObjectLacksException ignored) {}
} else {
return false;
}
return false;
}
@Override
public boolean clearParents() {
boolean work = false;
Iterator<Node> iterator = holder.getTransientNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (entry.isGroupNode()) {
iterator.remove();
work = true;
}
}
return work;
}
@Override
public boolean clearParents(Set<Context> set) {
Map<String, String> context = new HashMap<>();
for (Context c : set) {
context.put(c.getKey(), c.getValue());
}
boolean work = false;
Iterator<Node> iterator = holder.getTransientNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (!entry.isGroupNode()) {
continue;
}
if (entry.shouldApplyWithContext(context)) {
iterator.remove();
work = true;
}
}
return work;
}
@Override
public Map<Set<Context>, Map<String, String>> getAllOptions() {
Map<Set<Context>, Map<String, String>> options = new HashMap<>();
for (Node n : holder.getTransientNodes()) {
if (!n.isMeta()) {
continue;
}
Set<Context> contexts = n.getExtraContexts().entrySet().stream()
.map(entry -> new Context(entry.getKey(), entry.getValue()))
.collect(Collectors.toSet());
if (n.isServerSpecific()) {
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
}
if (n.isWorldSpecific()) {
contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get()));
}
if (!options.containsKey(contexts)) {
options.put(contexts, new HashMap<>());
}
options.get(contexts).put(unescapeCharacters(n.getMeta().getKey()), unescapeCharacters(n.getMeta().getValue()));
}
return ImmutableMap.copyOf(options);
}
@Override
public Map<String, String> getOptions(Set<Context> set) {
return ImmutableMap.copyOf(getAllOptions().getOrDefault(set, Collections.emptyMap()));
}
@Override
public boolean setOption(Set<Context> set, String key, String value) {
Map<String, String> context = new HashMap<>();
for (Context c : set) {
context.put(c.getKey(), c.getValue());
}
key = escapeCharacters(key);
value = escapeCharacters(value);
try {
holder.setTransientPermission(new me.lucko.luckperms.utils.Node.Builder("meta." + key + "." + value)
.withExtraContext(context)
.build()
);
} catch (ObjectAlreadyHasException ignored) {}
return true;
}
@Override
public boolean clearOptions(Set<Context> set) {
Map<String, String> context = new HashMap<>();
for (Context c : set) {
context.put(c.getKey(), c.getValue());
}
boolean work = false;
Iterator<Node> iterator = holder.getTransientNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (!entry.isMeta()) {
continue;
}
if (entry.shouldApplyWithContext(context)) {
iterator.remove();
work = true;
}
}
return work;
}
@Override
public boolean clearOptions() {
boolean work = false;
Iterator<Node> iterator = holder.getTransientNodes().iterator();
while (iterator.hasNext()) {
Node entry = iterator.next();
if (entry.isMeta()) {
iterator.remove();
work = true;
}
}
return work;
}
}
}
@@ -20,14 +20,14 @@
* SOFTWARE.
*/
package me.lucko.luckperms.service.collections;
package me.lucko.luckperms.api.sponge.collections;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.groups.GroupManager;
import me.lucko.luckperms.service.LuckPermsService;
import me.lucko.luckperms.service.simple.SimpleSubject;
import me.lucko.luckperms.service.wrapping.LuckPermsSubject;
import me.lucko.luckperms.api.sponge.LuckPermsService;
import me.lucko.luckperms.api.sponge.simple.SimpleSubject;
import me.lucko.luckperms.api.sponge.LuckPermsSubject;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.service.permission.Subject;
@@ -86,6 +86,6 @@ public class GroupCollection implements SubjectCollection {
@Override
public Subject getDefaults() {
return null;
return new SimpleSubject("default", service, this);
}
}
@@ -20,13 +20,13 @@
* SOFTWARE.
*/
package me.lucko.luckperms.service.collections;
package me.lucko.luckperms.api.sponge.collections;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.service.LuckPermsService;
import me.lucko.luckperms.service.simple.SimpleSubject;
import me.lucko.luckperms.service.wrapping.LuckPermsSubject;
import me.lucko.luckperms.api.sponge.LuckPermsService;
import me.lucko.luckperms.api.sponge.simple.SimpleSubject;
import me.lucko.luckperms.api.sponge.LuckPermsSubject;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.users.UserManager;
import org.spongepowered.api.service.context.Context;
@@ -66,7 +66,8 @@ public class UserCollection implements SubjectCollection {
}
}
// Wtf am I meant to do here? What if no user is loaded? Load it? Create it?
// What am I meant to do here? What if no user is loaded? Load it? Create it?
// If I do load/create it, this method should always be called async??.... errr.
return new SimpleSubject(id, service, this);
}
@@ -104,6 +105,6 @@ public class UserCollection implements SubjectCollection {
@Override
public Subject getDefaults() {
return null;
return new SimpleSubject("default", service, this);
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.service.simple;
package me.lucko.luckperms.api.sponge.simple;
import lombok.Getter;
import lombok.NonNull;
@@ -85,6 +85,6 @@ public class SimpleCollection implements SubjectCollection {
@Override
public Subject getDefaults() {
return null; // TODO
return new SimpleSubject("default", service, this);
}
}
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
package me.lucko.luckperms.service.simple;
package me.lucko.luckperms.api.sponge.simple;
import lombok.Getter;
import lombok.NonNull;
@@ -29,8 +29,9 @@ import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.*;
import org.spongepowered.api.util.Tristate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
* Super simple Subject implementation.
@@ -43,9 +44,6 @@ public class SimpleSubject implements Subject {
private final SubjectCollection containingCollection;
private final SubjectData subjectData;
private final Map<Set<Context>, Map<String, Tristate>> perms = new ConcurrentHashMap<>();
private final Map<Set<Context>, Set<Subject>> parents = new ConcurrentHashMap<>();
public SimpleSubject(String identifier, PermissionService service, SubjectCollection containingCollection) {
this.identifier = identifier;
this.service = service;
@@ -65,33 +63,21 @@ public class SimpleSubject implements Subject {
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return getPermissionValue(contexts, node).asBoolean();
return subjectData.getPermissions(contexts).getOrDefault(node, false);
}
@Override
public boolean hasPermission(@NonNull String permission) {
return getPermissionValue(getActiveContexts(), permission).asBoolean();
return hasPermission(getActiveContexts(), permission);
}
@Override
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
if (!perms.containsKey(contexts)) {
if (!subjectData.getPermissions(contexts).containsKey(node)) {
return Tristate.UNDEFINED;
}
Map<String, Tristate> context = perms.get(contexts);
if (context.containsKey(node)) {
return context.get(node);
}
for (Subject parent : getParents(contexts)) {
Tristate ts = parent.getPermissionValue(contexts, node);
if (ts != Tristate.UNDEFINED) {
return ts;
}
}
return Tristate.UNDEFINED;
return Tristate.fromBoolean(subjectData.getPermissions(contexts).get(node));
}
@Override
@@ -101,7 +87,7 @@ public class SimpleSubject implements Subject {
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject subject) {
return parents.containsKey(contexts) && parents.get(contexts).contains(subject);
return subjectData.getParents(contexts).contains(subject);
}
@Override
@@ -111,21 +97,17 @@ public class SimpleSubject implements Subject {
@Override
public List<Subject> getParents(@NonNull Set<Context> contexts) {
if (!parents.containsKey(contexts)) {
return Collections.emptyList();
}
return new ArrayList<>(parents.get(contexts));
return subjectData.getParents(contexts);
}
@Override
public Optional<String> getOption(Set<Context> set, String s) {
return null; // TODO
return Optional.ofNullable(subjectData.getOptions(set).get(s));
}
@Override
public Optional<String> getOption(String key) {
return null; // TODO
return Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key));
}
@Override
@@ -1,464 +0,0 @@
/*
* 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.service.wrapping;
import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NonNull;
import me.lucko.luckperms.constants.Patterns;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.service.LuckPermsService;
import me.lucko.luckperms.users.User;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.service.context.Context;
import org.spongepowered.api.service.permission.Subject;
import org.spongepowered.api.service.permission.SubjectCollection;
import org.spongepowered.api.service.permission.SubjectData;
import org.spongepowered.api.util.Tristate;
import java.util.*;
import java.util.stream.Collectors;
/**
* TODO
* this class is aids rn
*/
@AllArgsConstructor
public class LuckPermsSubject implements Subject {
private final EnduringData enduringData;
private final LuckPermsService service;
public LuckPermsSubject(PermissionHolder holder, LuckPermsService service) {
this.enduringData = new EnduringData(service, holder);
this.service = service;
}
@Override
public String getIdentifier() {
return enduringData.getHolder().getObjectName();
}
@Override
public Optional<CommandSource> getCommandSource() {
if (enduringData.getHolder() instanceof User) {
final UUID uuid = ((User) enduringData.getHolder()).getUuid();
Optional<Player> p = Sponge.getServer().getPlayer(uuid);
if (p.isPresent()) {
return Optional.of(p.get());
}
}
return Optional.empty();
}
@Override
public SubjectCollection getContainingCollection() {
if (enduringData.getHolder() instanceof Group) {
return service.getGroupSubjects();
} else {
return service.getUserSubjects();
}
}
@Override
public SubjectData getSubjectData() {
return null; // TODO
}
@Override
public SubjectData getTransientSubjectData() {
return null; // TODO
}
@Override
public boolean hasPermission(@NonNull Set<Context> contexts, @NonNull String node) {
return getPermissionValue(contexts, node).asBoolean();
}
@Override
public boolean hasPermission(String permission) {
return getPermissionValue(getActiveContexts(), permission).asBoolean();
}
@Override
public Tristate getPermissionValue(@NonNull Set<Context> contexts, @NonNull String node) {
return null;
/*
final Map<String, Boolean> nodes = applyContexts(contexts);
if (nodes.containsKey(node)) {
return Tristate.fromBoolean(nodes.get(node));
} else {
return Tristate.UNDEFINED;
}
*/
}
@Override
public boolean isChildOf(@NonNull Subject parent) {
return isChildOf(getActiveContexts(), parent);
}
@Override
public boolean isChildOf(@NonNull Set<Context> contexts, @NonNull Subject parent) {
return parent instanceof PermissionHolder && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean();
}
@Override
public List<Subject> getParents() {
return getParents(getActiveContexts());
}
@Override
public List<Subject> getParents(@NonNull Set<Context> contexts) {
return null;
}
@Override
public Optional<String> getOption(Set<Context> set, String s) {
return null;
}
@Override
public Optional<String> getOption(String key) {
return null;
}
@Override
public Set<Context> getActiveContexts() {
return SubjectData.GLOBAL_CONTEXT;
}
@AllArgsConstructor
public static class EnduringData implements SubjectData {
private final LuckPermsService service;
@Getter
private final PermissionHolder holder;
@Override
public Map<Set<Context>, Map<String, Boolean>> getAllPermissions() {
return null;
// TODO
/*
Map<String, Boolean> nodes = holder.convertTemporaryPerms();
Map<Set<Context>, Map<String, Boolean>> permissions = new HashMap<>();
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
String node = e.getKey();
if (node.contains("/")) {
// server and/or world specific
String[] parts = Patterns.SERVER_DELIMITER.split(node, 2);
// 0 = server+world 1 = node
node = parts[1];
String server = null;
String world = null;
if (parts[0].contains("-")) {
String[] serverParts = Patterns.WORLD_DELIMITER.split(parts[0], 2);
world = serverParts[0];
server = serverParts[1];
} else {
server = parts[0];
}
if (world == null) {
if (Patterns.NODE_CONTEXTS.matcher(node).matches()) {
// Has special context
Set<Context> c = Sets.newHashSet(new Context(LuckPermsService.SERVER_CONTEXT, server));
String[] contextParts = e.getKey().substring(1).split("\\)", 2);
// 0 = context, 1 = node
node = contextParts[1];
// Parse the context values from this node
for (String s : contextParts[0].split("\\,")) {
if (!s.contains("=")) {
// Not valid
continue;
}
// contextKey=value
String[] con = s.split("\\=", 2);
c.add(new Context(con[0], con[1]));
}
if (!permissions.containsKey(c)) {
permissions.put(c, new HashMap<>());
}
permissions.get(c).put(node, e.getValue());
} else {
// No special context
Set<Context> c = Sets.newHashSet(new Context(LuckPermsService.SERVER_CONTEXT, server));
if (!permissions.containsKey(c)) {
permissions.put(c, new HashMap<>());
}
permissions.get(c).put(node, e.getValue());
}
} else {
if (Patterns.NODE_CONTEXTS.matcher(node).matches()) {
// Has special context
Set<Context> c = Sets.newHashSet(new Context(Context.WORLD_KEY, world), new Context(LuckPermsService.SERVER_CONTEXT, server));
String[] contextParts = e.getKey().substring(1).split("\\)", 2);
// 0 = context, 1 = node
node = contextParts[1];
// Parse the context values from this node
for (String s : contextParts[0].split("\\,")) {
if (!s.contains("=")) {
// Not valid
continue;
}
// contextKey=value
String[] con = s.split("\\=", 2);
c.add(new Context(con[0], con[1]));
}
if (!permissions.containsKey(c)) {
permissions.put(c, new HashMap<>());
}
permissions.get(c).put(node, e.getValue());
} else {
// No special context
Set<Context> c = Sets.newHashSet(new Context(Context.WORLD_KEY, world), new Context(LuckPermsService.SERVER_CONTEXT, server));
if (!permissions.containsKey(c)) {
permissions.put(c, new HashMap<>());
}
permissions.get(c).put(node, e.getValue());
}
}
} else {
// Plain node
if (Patterns.NODE_CONTEXTS.matcher(e.getKey()).matches()) {
// Has special context
Set<Context> c = Sets.newHashSet();
String[] contextParts = e.getKey().substring(1).split("\\)", 2);
// 0 = context, 1 = node
node = contextParts[1];
// Parse the context values from this node
for (String s : contextParts[0].split("\\,")) {
if (!s.contains("=")) {
// Not valid
continue;
}
// contextKey=value
String[] con = s.split("\\=", 2);
c.add(new Context(con[0], con[1]));
}
if (!permissions.containsKey(c)) {
permissions.put(c, new HashMap<>());
}
permissions.get(c).put(node, e.getValue());
} else {
if (!permissions.containsKey(new HashSet<Context>())) {
permissions.put(new HashSet<>(), new HashMap<>());
}
permissions.get(new HashSet<Context>()).put(node, e.getValue());
}
}
}
return permissions;
*/
}
@Override
public Map<String, Boolean> getPermissions(Set<Context> set) {
return getAllPermissions().getOrDefault(set, Collections.emptyMap());
}
@Override
public boolean setPermission(Set<Context> set, String s, Tristate tristate) {
return false;
}
@Override
public boolean clearPermissions() {
return false;
}
@Override
public boolean clearPermissions(Set<Context> set) {
return false;
}
@Override
public Map<Set<Context>, List<Subject>> getAllParents() {
return null;
}
@Override
public List<Subject> getParents(Set<Context> contexts) {
final Set<String> parents = new HashSet<>();
final Map<String, Boolean> nodes = applyContexts(contexts);
for (Map.Entry<String, Boolean> e : nodes.entrySet()) {
if (!e.getValue()) {
continue;
}
if (Patterns.GROUP_MATCH.matcher(e.getKey()).matches()) {
final String groupName = e.getKey().substring("group.".length());
parents.add(groupName);
}
}
return parents.stream().map(s -> service.getGroupSubjects().get(s)).collect(Collectors.toList());
}
@Override
public boolean addParent(Set<Context> set, Subject subject) {
return false;
}
@Override
public boolean removeParent(Set<Context> set, Subject subject) {
return false;
}
@Override
public boolean clearParents() {
return false;
}
@Override
public boolean clearParents(Set<Context> set) {
return false;
}
@Override
public Map<Set<Context>, Map<String, String>> getAllOptions() {
return null;
}
@Override
public Map<String, String> getOptions(Set<Context> set) {
return null;
}
@Override
public boolean setOption(Set<Context> set, String s, String s1) {
return false;
}
@Override
public boolean clearOptions(Set<Context> set) {
return false;
}
@Override
public boolean clearOptions() {
return false;
}
private Map<String, Boolean> applyContexts(@NonNull Set<Context> set) {
final Map<String, Boolean> map = new HashMap<>();
String world = null;
String server = null;
Map<String, String> contexts = new HashMap<>();
for (Context context : set) {
if (context.getType().equals(Context.WORLD_KEY)) {
world = context.getName();
continue;
}
if (context.getType().equals(LuckPermsService.SERVER_CONTEXT)) {
server = context.getName();
continue;
}
contexts.put(context.getType(), context.getName());
}
Map<String, Boolean> local = holder.getLocalPermissions(server, world, null, service.getPossiblePermissions());
perms:
for (Map.Entry<String, Boolean> e : local.entrySet()) {
if (!contexts.isEmpty()) {
if (!Patterns.NODE_CONTEXTS.matcher(e.getKey()).matches()) {
continue;
}
String[] parts = e.getKey().substring(1).split("\\)", 2);
// 0 = context, 1 = node
// Parse the context values from this node
Map<String, String> contextValues = new HashMap<>();
for (String s : parts[0].split("\\,")) {
if (!s.contains("=")) {
// Not valid
continue;
}
// contextKey=value
String[] con = s.split("\\=", 2);
contextValues.put(con[0], con[1]);
}
// Check that all of the requested contexts are met
for (Map.Entry<String, String> req : contexts.entrySet()) {
if (!contextValues.containsKey(e.getKey())) {
continue;
}
if (!contextValues.get(req.getKey()).equalsIgnoreCase(req.getValue())) {
// Not valid within the current contexts
continue perms;
}
}
// Passed all da tests.
map.put(parts[1], e.getValue());
} else {
map.put(e.getKey(), e.getValue());
}
}
return map;
}
}
}