1
0
mirror of https://github.com/lucko/LuckPerms.git synced 2025-08-22 14:12:48 +02:00

Integrate log commands with new log backend method

This commit is contained in:
Luck
2024-06-10 22:06:58 +01:00
parent 3b5a936674
commit 73abf64aa3
43 changed files with 366 additions and 682 deletions

View File

@@ -26,7 +26,6 @@
package net.luckperms.api.event.sync;
import net.luckperms.api.event.LuckPermsEvent;
import net.luckperms.api.event.type.Cancellable;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

View File

@@ -37,7 +37,6 @@ import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.event.server.RemoteServerCommandEvent;
import org.bukkit.event.server.ServerCommandEvent;
import java.util.Locale;
import java.util.regex.Pattern;
public class BukkitPlatformListener implements Listener {

View File

@@ -1,112 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.actionlog;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import net.luckperms.api.actionlog.Action;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.UUID;
public class Log {
private static final Log EMPTY = new Log(ImmutableList.of());
public static Builder builder() {
return new Builder();
}
public static Log of(List<LoggedAction> content) {
return content.isEmpty() ? EMPTY : new Log(content);
}
public static Log empty() {
return EMPTY;
}
private final SortedSet<LoggedAction> content;
Log(List<LoggedAction> content) {
this.content = ImmutableSortedSet.copyOf(content);
}
public SortedSet<LoggedAction> getContent() {
return this.content;
}
public SortedSet<LoggedAction> getContent(UUID actor) {
return this.content.stream()
.filter(e -> e.getSource().getUniqueId().equals(actor))
.collect(ImmutableCollectors.toSortedSet());
}
public SortedSet<LoggedAction> getUserHistory(UUID uniqueId) {
return this.content.stream()
.filter(e -> e.getTarget().getType() == Action.Target.Type.USER)
.filter(e -> e.getTarget().getUniqueId().isPresent() && e.getTarget().getUniqueId().get().equals(uniqueId))
.collect(ImmutableCollectors.toSortedSet());
}
public SortedSet<LoggedAction> getGroupHistory(String name) {
return this.content.stream()
.filter(e -> e.getTarget().getType() == Action.Target.Type.GROUP)
.filter(e -> e.getTarget().getName().equals(name))
.collect(ImmutableCollectors.toSortedSet());
}
public SortedSet<LoggedAction> getTrackHistory(String name) {
return this.content.stream()
.filter(e -> e.getTarget().getType() == Action.Target.Type.TRACK)
.filter(e -> e.getTarget().getName().equals(name))
.collect(ImmutableCollectors.toSortedSet());
}
public SortedSet<LoggedAction> getSearch(String query) {
return this.content.stream()
.filter(e -> e.matchesSearch(query))
.collect(ImmutableCollectors.toSortedSet());
}
public static class Builder {
private final List<LoggedAction> content = new ArrayList<>();
public Builder add(LoggedAction e) {
this.content.add(e);
return this;
}
public Log build() {
if (this.content.isEmpty()) {
return EMPTY;
}
return new Log(this.content);
}
}
}

View File

@@ -26,48 +26,82 @@
package me.lucko.luckperms.common.actionlog;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.filter.PageParameters;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class LogPage {
private static final LogPage EMPTY = new LogPage(ImmutableList.of());
public static LogPage.Builder builder() {
return new LogPage.Builder();
}
public static LogPage of(List<LoggedAction> content) {
return content.isEmpty() ? EMPTY : new LogPage(content);
}
public static LogPage empty() {
return EMPTY;
public static LogPage of(List<LoggedAction> content, @Nullable PageParameters params, int totalEntries) {
return new LogPage(content, params, totalEntries);
}
private final List<LoggedAction> content;
private final @Nullable PageParameters params;
private final int totalEntries;
LogPage(List<LoggedAction> content) {
LogPage(List<LoggedAction> content, @Nullable PageParameters params, int totalEntries) {
this.content = ImmutableList.copyOf(content);
this.params = params;
this.totalEntries = totalEntries;
}
public List<LoggedAction> getContent() {
return this.content;
}
public static class Builder {
private final List<LoggedAction> content = new ArrayList<>();
public List<Entry<LoggedAction>> getNumberedContent() {
int startIndex = this.params != null
? this.params.pageSize() * (this.params.pageNumber() - 1)
: 0;
public Builder add(LoggedAction e) {
this.content.add(e);
return this;
List<Entry<LoggedAction>> numberedContent = new ArrayList<>();
for (int i = 0; i < this.content.size(); i++) {
int index = startIndex + i + 1;
numberedContent.add(new Entry<>(index, this.content.get(i)));
}
return numberedContent;
}
public int getTotalEntries() {
return this.totalEntries;
}
public static final class Entry<T> {
private final int position;
private final T value;
public Entry(int position, T value) {
this.position = position;
this.value = value;
}
public LogPage build() {
if (this.content.isEmpty()) {
return EMPTY;
}
return new LogPage(this.content);
public int position() {
return this.position;
}
public T value() {
return this.value;
}
@Override
public String toString() {
return this.position + ": " + this.value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Entry)) return false;
Entry<?> entry = (Entry<?>) o;
return this.position == entry.position && Objects.equals(this.value, entry.value);
}
@Override
public int hashCode() {
return Objects.hash(this.position, this.value);
}
}

View File

@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.actionlog.filter;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.filter.FilterField;
import me.lucko.luckperms.common.filter.mongo.FilterMongoBuilder;
import net.luckperms.api.actionlog.Action;

View File

@@ -97,13 +97,13 @@ public final class ActionFilters {
@Override
public Predicate<Target.Type> similar(Target.Type value) {
Pattern pattern = Comparison.compilePatternForLikeSyntax(value.toString());
return uuid -> pattern.matcher(uuid.toString()).matches();
return type -> pattern.matcher(type.toString()).matches();
}
@Override
public Predicate<Target.Type> notSimilar(Target.Type value) {
Pattern pattern = Comparison.compilePatternForLikeSyntax(value.toString());
return uuid -> !pattern.matcher(uuid.toString()).matches();
return type -> !pattern.matcher(type.toString()).matches();
}
};

View File

@@ -25,50 +25,62 @@
package me.lucko.luckperms.common.api.implementation;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.api.ApiUtils;
import com.google.common.collect.ImmutableSortedSet;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.util.ImmutableCollectors;
import net.luckperms.api.actionlog.Action;
import net.luckperms.api.actionlog.ActionLog;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.util.List;
import java.util.Objects;
import java.util.SortedSet;
import java.util.UUID;
@SuppressWarnings({"unchecked", "rawtypes"})
public class ApiActionLog implements ActionLog {
private final Log handle;
private final SortedSet<Action> content;
public ApiActionLog(Log handle) {
this.handle = handle;
public ApiActionLog(List<LoggedAction> content) {
this.content = ImmutableSortedSet.copyOf(content);
}
@Override
public @NonNull SortedSet<Action> getContent() {
return (SortedSet) this.handle.getContent();
return this.content;
}
@Override
public @NonNull SortedSet<Action> getContent(@NonNull UUID actor) {
Objects.requireNonNull(actor, "actor");
return (SortedSet) this.handle.getContent(actor);
return this.content.stream()
.filter(e -> e.getSource().getUniqueId().equals(actor))
.collect(ImmutableCollectors.toSortedSet());
}
@Override
public @NonNull SortedSet<Action> getUserHistory(@NonNull UUID uniqueId) {
Objects.requireNonNull(uniqueId, "uuid");
return (SortedSet) this.handle.getUserHistory(uniqueId);
return this.content.stream()
.filter(e -> e.getTarget().getType() == Action.Target.Type.USER)
.filter(e -> e.getTarget().getUniqueId().isPresent() && e.getTarget().getUniqueId().get().equals(uniqueId))
.collect(ImmutableCollectors.toSortedSet());
}
@Override
public @NonNull SortedSet<Action> getGroupHistory(@NonNull String name) {
Objects.requireNonNull(name, "name");
return (SortedSet) this.handle.getGroupHistory(ApiUtils.checkName(name));
return this.content.stream()
.filter(e -> e.getTarget().getType() == Action.Target.Type.GROUP)
.filter(e -> e.getTarget().getName().equals(name))
.collect(ImmutableCollectors.toSortedSet());
}
@Override
public @NonNull SortedSet<Action> getTrackHistory(@NonNull String name) {
Objects.requireNonNull(name, "name");
return (SortedSet) this.handle.getTrackHistory(ApiUtils.checkName(name));
return this.content.stream()
.filter(e -> e.getTarget().getType() == Action.Target.Type.TRACK)
.filter(e -> e.getTarget().getName().equals(name))
.collect(ImmutableCollectors.toSortedSet());
}
}

View File

@@ -26,6 +26,7 @@
package me.lucko.luckperms.common.api.implementation;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import net.luckperms.api.actionlog.Action;
import net.luckperms.api.actionlog.ActionLog;
@@ -48,7 +49,8 @@ public class ApiActionLogger implements ActionLogger {
@Override
public @NonNull CompletableFuture<ActionLog> getLog() {
return this.plugin.getStorage().getLog().thenApply(ApiActionLog::new);
return this.plugin.getStorage().getLogPage(ActionFilters.all(), null)
.thenApply(result -> new ApiActionLog(result.getContent()));
}
@Override

View File

@@ -26,14 +26,12 @@
package me.lucko.luckperms.common.bulkupdate;
import me.lucko.luckperms.common.bulkupdate.action.BulkUpdateAction;
import me.lucko.luckperms.common.filter.Filter;
import me.lucko.luckperms.common.filter.FilterList;
import me.lucko.luckperms.common.model.HolderType;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

View File

@@ -28,7 +28,6 @@ package me.lucko.luckperms.common.bulkupdate;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.bulkupdate.action.BulkUpdateAction;
import me.lucko.luckperms.common.filter.Comparison;
import me.lucko.luckperms.common.filter.Constraint;
import me.lucko.luckperms.common.filter.ConstraintFactory;
import me.lucko.luckperms.common.filter.Filter;
import me.lucko.luckperms.common.filter.FilterList;

View File

@@ -64,10 +64,6 @@ public class BulkUpdateSqlBuilder extends FilterSqlBuilder<Node> {
this.builder.append("DELETE FROM {table}");
}
public void visit(List<Filter<Node, String>> filters) {
visit(FilterList.LogicalOperator.AND, filters);
}
@Override
public void visitFieldName(FilterField<Node, ?> field) {
if (field == BulkUpdateField.PERMISSION) {

View File

@@ -86,39 +86,44 @@ public abstract class ParentCommand<T, I> extends Command<Void> {
return;
}
final String targetArgument = args.get(0);
I targetId = null;
if (this.type == Type.TAKES_ARGUMENT_FOR_TARGET) {
targetId = parseTarget(targetArgument, plugin, sender);
if (this.type == Type.TARGETED) {
final String targetArgument = args.get(0);
I targetId = parseTarget(targetArgument, plugin, sender);
if (targetId == null) {
return;
}
}
ReentrantLock lock = getLockForTarget(targetId);
lock.lock();
try {
T target = getTarget(targetId, plugin, sender);
if (target == null) {
return;
}
ReentrantLock lock = getLockForTarget(targetId);
lock.lock();
try {
sub.execute(plugin, sender, target, args.subList(this.type.minArgs, args.size()), label);
T target = getTarget(targetId, plugin, sender);
if (target == null) {
return;
}
try {
sub.execute(plugin, sender, target, args.subList(this.type.minArgs, args.size()), label);
} catch (CommandException e) {
e.handle(sender, label, sub);
}
cleanup(target, plugin);
} finally {
lock.unlock();
}
} else {
try {
sub.execute(plugin, sender, null, args.subList(this.type.minArgs, args.size()), label);
} catch (CommandException e) {
e.handle(sender, label, sub);
}
cleanup(target, plugin);
} finally {
lock.unlock();
}
}
@Override
public List<String> tabComplete(LuckPermsPlugin plugin, Sender sender, ArgumentList args) {
switch (this.type) {
case TAKES_ARGUMENT_FOR_TARGET:
case TARGETED:
return TabCompleter.create()
.at(0, CompletionSupplier.startsWith(() -> getTargets(plugin).stream()))
.at(1, CompletionSupplier.startsWith(() -> getChildren().stream()
@@ -133,7 +138,7 @@ public abstract class ParentCommand<T, I> extends Command<Void> {
.orElse(Collections.emptyList())
)
.complete(args);
case NO_TARGET_ARGUMENT:
case NOT_TARGETED:
return TabCompleter.create()
.at(0, CompletionSupplier.startsWith(() -> getChildren().stream()
.filter(s -> s.isAuthorized(sender))
@@ -178,21 +183,31 @@ public abstract class ParentCommand<T, I> extends Command<Void> {
return getChildren().stream().anyMatch(sc -> sc.isAuthorized(sender));
}
protected abstract List<String> getTargets(LuckPermsPlugin plugin);
protected List<String> getTargets(LuckPermsPlugin plugin) {
throw new UnsupportedOperationException();
}
protected abstract I parseTarget(String target, LuckPermsPlugin plugin, Sender sender);
protected I parseTarget(String target, LuckPermsPlugin plugin, Sender sender) {
throw new UnsupportedOperationException();
}
protected abstract ReentrantLock getLockForTarget(I target);
protected ReentrantLock getLockForTarget(I target) {
throw new UnsupportedOperationException();
}
protected abstract T getTarget(I target, LuckPermsPlugin plugin, Sender sender);
protected T getTarget(I target, LuckPermsPlugin plugin, Sender sender) {
throw new UnsupportedOperationException();
}
protected abstract void cleanup(T t, LuckPermsPlugin plugin);
protected void cleanup(T t, LuckPermsPlugin plugin) {
throw new UnsupportedOperationException();
}
public enum Type {
// e.g. /lp log sub-command....
NO_TARGET_ARGUMENT(0),
NOT_TARGETED(0),
// e.g. /lp user <USER> sub-command....
TAKES_ARGUMENT_FOR_TARGET(1);
TARGETED(1);
private final int cmdIndex;
private final int minArgs;

View File

@@ -60,7 +60,7 @@ public class GroupParentCommand extends ParentCommand<Group, String> {
.build(key -> new ReentrantLock());
public GroupParentCommand() {
super(CommandSpec.GROUP, "Group", Type.TAKES_ARGUMENT_FOR_TARGET, ImmutableList.<Command<Group>>builder()
super(CommandSpec.GROUP, "Group", Type.TARGETED, ImmutableList.<Command<Group>>builder()
.add(new GroupInfo())
.add(new CommandPermission<>(HolderType.GROUP))
.add(new CommandParent<>(HolderType.GROUP))

View File

@@ -25,25 +25,26 @@
package me.lucko.luckperms.common.commands.log;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.misc.DataConstraints;
import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
import java.util.Locale;
public class LogGroupHistory extends ChildCommand<Log> {
public class LogGroupHistory extends ChildCommand<Void> {
private static final int ENTRIES_PER_PAGE = 10;
public LogGroupHistory() {
@@ -51,44 +52,34 @@ public class LogGroupHistory extends ChildCommand<Log> {
}
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
String group = args.get(0).toLowerCase(Locale.ROOT);
if (!DataConstraints.GROUP_NAME_TEST.test(group)) {
Message.GROUP_INVALID_ENTRY.send(sender, group);
return;
}
Paginated<LoggedAction> content = new Paginated<>(log.getGroupHistory(group));
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, Integer.MIN_VALUE));
LogPage log = plugin.getStorage().getLogPage(ActionFilters.group(group), pageParams).join();
int page = args.getIntOrDefault(1, Integer.MIN_VALUE);
if (page != Integer.MIN_VALUE) {
showLog(page, sender, content);
} else {
showLog(content.getMaxPages(ENTRIES_PER_PAGE), sender, content);
}
}
int page = pageParams.pageNumber();
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
private static void showLog(int page, Sender sender, Paginated<LoggedAction> log) {
int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
if (maxPage == 0) {
if (log.getContent().isEmpty()) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
if (page == Integer.MIN_VALUE) {
page = maxPage;
}
if (page < 1 || page > maxPage) {
Message.LOG_INVALID_PAGE_RANGE.send(sender, maxPage);
return;
}
List<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
String name = entries.stream().findAny().get().value().getTarget().getName();
Message.LOG_HISTORY_GROUP_HEADER.send(sender, name, page, maxPage);
for (Paginated.Entry<LoggedAction> e : entries) {
for (LogPage.Entry<LoggedAction> e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}

View File

@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.log;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
@@ -43,7 +42,7 @@ import net.luckperms.api.node.Node;
import java.util.Optional;
import java.util.UUID;
public class LogNotify extends ChildCommand<Log> {
public class LogNotify extends ChildCommand<Void> {
private static final String IGNORE_NODE = "luckperms.log.notify.ignoring";
public LogNotify() {
@@ -83,7 +82,7 @@ public class LogNotify extends ChildCommand<Log> {
}
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
if (sender.isConsole()) {
Message.LOG_NOTIFY_CONSOLE.send(sender);
return;

View File

@@ -26,22 +26,13 @@
package me.lucko.luckperms.common.commands.log;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.command.abstraction.Command;
import me.lucko.luckperms.common.command.abstraction.ParentCommand;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
public class LogParentCommand extends ParentCommand<Log, Void> {
private final ReentrantLock lock = new ReentrantLock();
public class LogParentCommand extends ParentCommand<Void, Void> {
public LogParentCommand() {
super(CommandSpec.LOG, "Log", Type.NO_TARGET_ARGUMENT, ImmutableList.<Command<Log>>builder()
super(CommandSpec.LOG, "Log", Type.NOT_TARGETED, ImmutableList.<Command<Void>>builder()
.add(new LogRecent())
.add(new LogSearch())
.add(new LogNotify())
@@ -51,38 +42,4 @@ public class LogParentCommand extends ParentCommand<Log, Void> {
.build()
);
}
@Override
protected ReentrantLock getLockForTarget(Void target) {
return this.lock; // all commands target the same log, so we share a lock between all "targets"
}
@Override
protected Log getTarget(Void target, LuckPermsPlugin plugin, Sender sender) {
Log log = plugin.getStorage().getLog().join();
if (log == null) {
Message.LOG_LOAD_ERROR.send(sender);
}
return log;
}
@Override
protected void cleanup(Log log, LuckPermsPlugin plugin) {
}
@Override
protected List<String> getTargets(LuckPermsPlugin plugin) {
// should never be called if we specify Type.NO_TARGET_ARGUMENT in the constructor
throw new UnsupportedOperationException();
}
@Override
protected Void parseTarget(String target, LuckPermsPlugin plugin, Sender sender) {
// should never be called if we specify Type.NO_TARGET_ARGUMENT in the constructor
throw new UnsupportedOperationException();
}
}

View File

@@ -25,22 +25,23 @@
package me.lucko.luckperms.common.commands.log;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
import java.util.UUID;
public class LogRecent extends ChildCommand<Log> {
public class LogRecent extends ChildCommand<Void> {
private static final int ENTRIES_PER_PAGE = 10;
public LogRecent() {
@@ -48,39 +49,32 @@ public class LogRecent extends ChildCommand<Log> {
}
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
if (args.isEmpty()) {
// No page or user
Paginated<LoggedAction> content = new Paginated<>(log.getContent());
showLog(content.getMaxPages(ENTRIES_PER_PAGE), false, sender, content);
return;
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
int page = 1;
UUID uuid = null;
if (!args.isEmpty()) {
int pageNo = args.getIntOrDefault(0, Integer.MIN_VALUE);
if (pageNo != Integer.MIN_VALUE) {
page = pageNo;
} else {
uuid = args.getUserTarget(0, plugin, sender);
if (uuid == null) {
return;
}
pageNo = args.getIntOrDefault(1, Integer.MIN_VALUE);
if (pageNo != Integer.MIN_VALUE) {
page = pageNo;
}
}
}
int page = args.getIntOrDefault(0, Integer.MIN_VALUE);
if (page != Integer.MIN_VALUE) {
Paginated<LoggedAction> content = new Paginated<>(log.getContent());
showLog(page, false, sender, content);
return;
}
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, page);
LogPage log = plugin.getStorage().getLogPage(uuid == null ? ActionFilters.all() : ActionFilters.source(uuid), pageParams).join();
// User and possibly page
UUID uuid = args.getUserTarget(0, plugin, sender);
if (uuid == null) {
return;
}
Paginated<LoggedAction> content = new Paginated<>(log.getContent(uuid));
page = args.getIntOrDefault(1, Integer.MIN_VALUE);
if (page != Integer.MIN_VALUE) {
showLog(page, true, sender, content);
} else {
showLog(content.getMaxPages(ENTRIES_PER_PAGE), true, sender, content);
}
}
private static void showLog(int page, boolean specificUser, Sender sender, Paginated<LoggedAction> log) {
int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
if (maxPage == 0) {
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
if (log.getContent().isEmpty()) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
@@ -90,8 +84,8 @@ public class LogRecent extends ChildCommand<Log> {
return;
}
List<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
if (specificUser) {
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
if (uuid != null) {
String name = entries.stream().findAny().get().value().getSource().getName();
if (name.contains("@")) {
name = name.split("@")[0];
@@ -101,8 +95,9 @@ public class LogRecent extends ChildCommand<Log> {
Message.LOG_RECENT_HEADER.send(sender, page, maxPage);
}
for (Paginated.Entry<LoggedAction> e : entries) {
for (LogPage.Entry<LoggedAction> e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}
}

View File

@@ -25,21 +25,22 @@
package me.lucko.luckperms.common.commands.log;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
public class LogSearch extends ChildCommand<Log> {
public class LogSearch extends ChildCommand<Void> {
private static final int ENTRIES_PER_PAGE = 10;
public LogSearch() {
@@ -47,7 +48,7 @@ public class LogSearch extends ChildCommand<Log> {
}
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
int page = Integer.MIN_VALUE;
if (args.size() > 1) {
try {
@@ -59,36 +60,26 @@ public class LogSearch extends ChildCommand<Log> {
}
final String query = String.join(" ", args);
Paginated<LoggedAction> content = new Paginated<>(log.getSearch(query));
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, page);
LogPage log = plugin.getStorage().getLogPage(ActionFilters.search(query), pageParams).join();
if (page != Integer.MIN_VALUE) {
showLog(page, query, sender, content);
} else {
showLog(content.getMaxPages(ENTRIES_PER_PAGE), query, sender, content);
}
}
private static void showLog(int page, String query, Sender sender, Paginated<LoggedAction> log) {
int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
if (maxPage == 0) {
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
if (log.getContent().isEmpty()) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
if (page == Integer.MIN_VALUE) {
page = maxPage;
}
if (page < 1 || page > maxPage) {
Message.LOG_INVALID_PAGE_RANGE.send(sender, maxPage);
return;
}
List<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
Message.LOG_SEARCH_HEADER.send(sender, query, page, maxPage);
for (Paginated.Entry<LoggedAction> e : entries) {
for (LogPage.Entry<LoggedAction> e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}
}

View File

@@ -25,25 +25,26 @@
package me.lucko.luckperms.common.commands.log;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.misc.DataConstraints;
import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
import java.util.Locale;
public class LogTrackHistory extends ChildCommand<Log> {
public class LogTrackHistory extends ChildCommand<Void> {
private static final int ENTRIES_PER_PAGE = 10;
public LogTrackHistory() {
@@ -51,44 +52,33 @@ public class LogTrackHistory extends ChildCommand<Log> {
}
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
String track = args.get(0).toLowerCase(Locale.ROOT);
if (!DataConstraints.TRACK_NAME_TEST.test(track)) {
Message.TRACK_INVALID_ENTRY.send(sender, track);
return;
}
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, Integer.MIN_VALUE));
LogPage log = plugin.getStorage().getLogPage(ActionFilters.track(track), pageParams).join();
Paginated<LoggedAction> content = new Paginated<>(log.getTrackHistory(track));
int page = pageParams.pageNumber();
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
int page = args.getIntOrDefault(1, Integer.MIN_VALUE);
if (page != Integer.MIN_VALUE) {
showLog(page, sender, content);
} else {
showLog(content.getMaxPages(ENTRIES_PER_PAGE), sender, content);
}
}
private static void showLog(int page, Sender sender, Paginated<LoggedAction> log) {
int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
if (maxPage == 0) {
if (log.getContent().isEmpty()) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
if (page == Integer.MIN_VALUE) {
page = maxPage;
}
if (page < 1 || page > maxPage) {
Message.LOG_INVALID_PAGE_RANGE.send(sender, maxPage);
return;
}
List<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
String name = entries.stream().findAny().get().value().getTarget().getName();
Message.LOG_HISTORY_TRACK_HEADER.send(sender, name, page, maxPage);
for (Paginated.Entry<LoggedAction> e : entries) {
for (LogPage.Entry<LoggedAction> e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}

View File

@@ -25,22 +25,23 @@
package me.lucko.luckperms.common.commands.log;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
import java.util.UUID;
public class LogUserHistory extends ChildCommand<Log> {
public class LogUserHistory extends ChildCommand<Void> {
private static final int ENTRIES_PER_PAGE = 10;
public LogUserHistory() {
@@ -48,25 +49,19 @@ public class LogUserHistory extends ChildCommand<Log> {
}
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
UUID uuid = args.getUserTarget(0, plugin, sender);
if (uuid == null) {
return;
}
Paginated<LoggedAction> content = new Paginated<>(log.getUserHistory(uuid));
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, Integer.MIN_VALUE));
LogPage log = plugin.getStorage().getLogPage(ActionFilters.user(uuid), pageParams).join();
int page = args.getIntOrDefault(1, Integer.MIN_VALUE);
if (page != Integer.MIN_VALUE) {
showLog(page, sender, content);
} else {
showLog(content.getMaxPages(ENTRIES_PER_PAGE), sender, content);
}
}
int page = pageParams.pageNumber();
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
private static void showLog(int page, Sender sender, Paginated<LoggedAction> log) {
int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
if (maxPage == 0) {
if (log.getContent().isEmpty()) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
@@ -76,11 +71,11 @@ public class LogUserHistory extends ChildCommand<Log> {
return;
}
List<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
String name = entries.stream().findAny().get().value().getTarget().getName();
Message.LOG_HISTORY_USER_HEADER.send(sender, name, page, maxPage);
for (Paginated.Entry<LoggedAction> e : entries) {
for (LogPage.Entry<LoggedAction> e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}

View File

@@ -53,7 +53,7 @@ public class TrackParentCommand extends ParentCommand<Track, String> {
.build(key -> new ReentrantLock());
public TrackParentCommand() {
super(CommandSpec.TRACK, "Track", Type.TAKES_ARGUMENT_FOR_TARGET, ImmutableList.<Command<Track>>builder()
super(CommandSpec.TRACK, "Track", Type.TARGETED, ImmutableList.<Command<Track>>builder()
.add(new TrackInfo())
.add(new TrackEditor())
.add(new TrackAppend())

View File

@@ -62,7 +62,7 @@ public class UserParentCommand extends ParentCommand<User, UserIdentifier> {
.build(key -> new ReentrantLock());
public UserParentCommand() {
super(CommandSpec.USER, "User", Type.TAKES_ARGUMENT_FOR_TARGET, ImmutableList.<Command<User>>builder()
super(CommandSpec.USER, "User", Type.TARGETED, ImmutableList.<Command<User>>builder()
.add(new UserInfo())
.add(new CommandPermission<>(HolderType.USER))
.add(new CommandParent<>(HolderType.USER))

View File

@@ -35,6 +35,13 @@ public class PageParameters {
private final int pageNumber;
public PageParameters(int pageSize, int pageNumber) {
if (pageSize < 1) {
throw new IllegalArgumentException("pageSize cannot be less than 1: " + pageSize);
}
if (pageNumber < 1) {
throw new IllegalArgumentException("pageNumber cannot be less than 1: " + pageNumber);
}
this.pageSize = pageSize;
this.pageNumber = pageNumber;
}
@@ -61,4 +68,12 @@ public class PageParameters {
return input.skip((long) this.pageSize * (this.pageNumber - 1)).limit(this.pageSize);
}
public int getMaxPage(int totalEntries) {
if (totalEntries == 0) {
return 0;
}
return (totalEntries + this.pageSize - 1) / this.pageSize;
}
}

View File

@@ -31,6 +31,7 @@ import me.lucko.luckperms.common.filter.Comparison;
import me.lucko.luckperms.common.filter.Constraint;
import me.lucko.luckperms.common.filter.PageParameters;
import org.bson.conversions.Bson;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.regex.Pattern;
@@ -73,9 +74,13 @@ public class ConstraintMongoBuilder {
}
}
public static <R> FindIterable<R> page(PageParameters pageParameters, FindIterable<R> iterable) {
int pageSize = pageParameters.pageSize();
int pageNumber = pageParameters.pageNumber();
public static <R> FindIterable<R> page(@Nullable PageParameters params, FindIterable<R> iterable) {
if (params == null) {
return iterable;
}
int pageSize = params.pageSize();
int pageNumber = params.pageNumber();
return iterable.limit(pageSize).skip((pageNumber - 1) * pageSize);
}

View File

@@ -4,6 +4,7 @@ import me.lucko.luckperms.common.filter.Comparison;
import me.lucko.luckperms.common.filter.Constraint;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.storage.implementation.sql.builder.AbstractSqlBuilder;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ConstraintSqlBuilder extends AbstractSqlBuilder {
@@ -45,9 +46,13 @@ public class ConstraintSqlBuilder extends AbstractSqlBuilder {
}
}
public void visit(PageParameters pageParameters) {
int pageSize = pageParameters.pageSize();
int pageNumber = pageParameters.pageNumber();
public void visit(@Nullable PageParameters params) {
if (params == null) {
return;
}
int pageSize = params.pageSize();
int pageNumber = params.pageNumber();
this.builder.append(" LIMIT " + pageSize + " OFFSET " + (pageNumber - 1) * pageSize);
}

View File

@@ -26,11 +26,10 @@
package me.lucko.luckperms.common.storage;
import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.filter.FilterList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User;
@@ -45,6 +44,7 @@ import net.luckperms.api.event.cause.CreationCause;
import net.luckperms.api.event.cause.DeletionCause;
import net.luckperms.api.model.PlayerSaveResult;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Collection;
import java.util.Collections;
@@ -136,11 +136,7 @@ public class Storage {
return future(() -> this.implementation.logAction(entry));
}
public CompletableFuture<Log> getLog() {
return future(this.implementation::getLog);
}
public CompletableFuture<LogPage> getLogPage(FilterList<Action> filters, PageParameters page) {
public CompletableFuture<LogPage> getLogPage(FilterList<Action> filters, @Nullable PageParameters page) {
return future(() -> this.implementation.getLogPage(filters, page));
}

View File

@@ -25,11 +25,10 @@
package me.lucko.luckperms.common.storage.implementation;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.filter.FilterList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User;
@@ -61,9 +60,7 @@ public interface StorageImplementation {
void logAction(Action entry) throws Exception;
Log getLog() throws Exception;
LogPage getLogPage(FilterList<Action> filters, PageParameters page) throws Exception;
LogPage getLogPage(FilterList<Action> filters, @Nullable PageParameters page) throws Exception;
void applyBulkUpdate(BulkUpdate bulkUpdate) throws Exception;

View File

@@ -26,7 +26,6 @@
package me.lucko.luckperms.common.storage.implementation.file;
import com.google.common.collect.Iterables;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
@@ -62,6 +61,7 @@ import net.luckperms.api.node.types.InheritanceNode;
import net.luckperms.api.node.types.MetaNode;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.Types;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.IOException;
import java.nio.file.Path;
@@ -171,12 +171,7 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
}
@Override
public Log getLog() throws IOException {
return this.actionLogger.getLog();
}
@Override
public LogPage getLogPage(FilterList<Action> filters, PageParameters page) throws Exception {
public LogPage getLogPage(FilterList<Action> filters, @Nullable PageParameters page) throws Exception {
return this.actionLogger.getLogPage(filters, page);
}

View File

@@ -25,12 +25,10 @@
package me.lucko.luckperms.common.storage.implementation.file;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.stream.JsonReader;
import me.lucko.luckperms.common.actionlog.ActionJsonSerializer;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.cache.BufferedRequest;
@@ -39,6 +37,7 @@ import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import net.luckperms.api.actionlog.Action;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.BufferedReader;
import java.io.IOException;
@@ -163,12 +162,15 @@ public class FileActionLogger {
return builder.build();
}
public Log getLog() throws IOException {
return Log.of(getRawLog().collect(Collectors.toList()));
}
public LogPage getLogPage(FilterList<Action> filters, @Nullable PageParameters page) throws IOException {
List<LoggedAction> filtered = getRawLog()
.filter(filters::evaluate)
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
public LogPage getLogPage(FilterList<Action> filters, PageParameters page) throws IOException {
return LogPage.of(page.paginate(getRawLog().filter(filters::evaluate).sorted(Comparator.reverseOrder())).collect(Collectors.toList()));
int size = filtered.size();
List<LoggedAction> paginated = page != null ? page.paginate(filtered) : filtered;
return LogPage.of(paginated, page, size);
}
private final class SaveBuffer extends BufferedRequest<Void> {

View File

@@ -31,23 +31,20 @@ import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientURI;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.ReplaceOptions;
import com.mongodb.client.model.Sorts;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.actionlog.filter.ActionFilterMongoBuilder;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.context.MutableContextSetImpl;
import me.lucko.luckperms.common.filter.mongo.ConstraintMongoBuilder;
import me.lucko.luckperms.common.filter.FilterList;
import me.lucko.luckperms.common.filter.mongo.FilterMongoBuilder;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.filter.mongo.ConstraintMongoBuilder;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.model.Track;
@@ -73,6 +70,7 @@ import net.luckperms.api.node.NodeBuilder;
import org.bson.Document;
import org.bson.UuidRepresentation;
import org.bson.conversions.Bson;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.time.Instant;
import java.util.ArrayList;
@@ -181,27 +179,20 @@ public class MongoStorage implements StorageImplementation {
}
@Override
public Log getLog() {
Log.Builder log = Log.builder();
MongoCollection<Document> c = this.database.getCollection(this.prefix + "action");
try (MongoCursor<Document> cursor = c.find().iterator()) {
while (cursor.hasNext()) {
log.add(actionFromDoc(cursor.next()));
}
}
return log.build();
}
public LogPage getLogPage(FilterList<Action> filters, @Nullable PageParameters page) throws Exception {
Bson filter = ActionFilterMongoBuilder.INSTANCE.make(filters);
@Override
public LogPage getLogPage(FilterList<Action> filters, PageParameters page) throws Exception {
LogPage.Builder log = LogPage.builder();
MongoCollection<Document> c = this.database.getCollection(this.prefix + "action");
try (MongoCursor<Document> cursor = ConstraintMongoBuilder.page(page, c.find(ActionFilterMongoBuilder.INSTANCE.make(filters)).sort(Sorts.descending("timestamp"))).iterator()) {
long count = c.countDocuments(filter);
List<LoggedAction> content = new ArrayList<>();
try (MongoCursor<Document> cursor = ConstraintMongoBuilder.page(page, c.find(filter).sort(Sorts.descending("timestamp"))).iterator()) {
while (cursor.hasNext()) {
log.add(actionFromDoc(cursor.next()));
content.add(actionFromDoc(cursor.next()));
}
}
return log.build();
return LogPage.of(content, page, (int) count);
}
@Override

View File

@@ -26,7 +26,6 @@
package me.lucko.luckperms.common.storage.implementation.split;
import com.google.common.collect.ImmutableMap;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.filter.FilterList;
@@ -43,6 +42,7 @@ import me.lucko.luckperms.common.storage.misc.NodeEntry;
import net.luckperms.api.actionlog.Action;
import net.luckperms.api.model.PlayerSaveResult;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List;
import java.util.Map;
@@ -121,12 +121,7 @@ public class SplitStorage implements StorageImplementation {
}
@Override
public Log getLog() throws Exception {
return implFor(SplitStorageType.LOG).getLog();
}
@Override
public LogPage getLogPage(FilterList<Action> filters, PageParameters page) throws Exception {
public LogPage getLogPage(FilterList<Action> filters, @Nullable PageParameters page) throws Exception {
return implFor(SplitStorageType.LOG).getLogPage(filters, page);
}

View File

@@ -28,7 +28,6 @@ package me.lucko.luckperms.common.storage.implementation.sql;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.gson.reflect.TypeToken;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.actionlog.filter.ActionFilterSqlBuilder;
@@ -36,9 +35,9 @@ import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.bulkupdate.BulkUpdateSqlBuilder;
import me.lucko.luckperms.common.bulkupdate.BulkUpdateStatistics;
import me.lucko.luckperms.common.context.serializer.ContextSetJsonSerializer;
import me.lucko.luckperms.common.filter.sql.ConstraintSqlBuilder;
import me.lucko.luckperms.common.filter.FilterList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.filter.sql.ConstraintSqlBuilder;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User;
@@ -59,6 +58,7 @@ import net.luckperms.api.context.DefaultContextKeys;
import net.luckperms.api.context.MutableContextSet;
import net.luckperms.api.model.PlayerSaveResult;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.IOException;
import java.io.InputStream;
@@ -132,6 +132,7 @@ public class SqlStorage implements StorageImplementation {
private static final String ACTION_INSERT = "INSERT INTO '{prefix}actions' (time, actor_uuid, actor_name, type, acted_uuid, acted_name, action) VALUES(?, ?, ?, ?, ?, ?, ?)";
private static final String ACTION_SELECT_ALL = "SELECT * FROM '{prefix}actions'";
private static final String ACTION_COUNT = "SELECT COUNT(*) FROM '{prefix}actions'";
private final LuckPermsPlugin plugin;
@@ -247,24 +248,23 @@ public class SqlStorage implements StorageImplementation {
}
@Override
public Log getLog() throws SQLException {
final Log.Builder log = Log.builder();
public LogPage getLogPage(FilterList<Action> filter, @Nullable PageParameters page) throws SQLException {
int count = 0;
List<LoggedAction> content = new ArrayList<>();
try (Connection c = this.connectionFactory.getConnection()) {
try (PreparedStatement ps = c.prepareStatement(this.statementProcessor.apply(ACTION_SELECT_ALL))) {
ActionFilterSqlBuilder countSqlBuilder = new ActionFilterSqlBuilder();
countSqlBuilder.builder().append(ACTION_COUNT);
countSqlBuilder.visit(filter);
try (PreparedStatement ps = countSqlBuilder.builder().build(c, this.statementProcessor)) {
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
log.add(readAction(rs));
if (rs.next()) {
count = rs.getInt(1);
}
}
}
}
return log.build();
}
@Override
public LogPage getLogPage(FilterList<Action> filter, PageParameters page) throws SQLException {
LogPage.Builder builder = LogPage.builder();
try (Connection c = this.connectionFactory.getConnection()) {
ActionFilterSqlBuilder sqlBuilder = new ActionFilterSqlBuilder();
sqlBuilder.builder().append(ACTION_SELECT_ALL);
sqlBuilder.visit(filter);
@@ -274,12 +274,12 @@ public class SqlStorage implements StorageImplementation {
try (PreparedStatement ps = sqlBuilder.builder().build(c, this.statementProcessor)) {
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
builder.add(readAction(rs));
content.add(readAction(rs));
}
}
}
}
return builder.build();
return LogPage.of(content, page, count);
}
@Override

View File

@@ -1,112 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.util;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/**
* A simple pagination utility
*
* @param <T> the element type
*/
public class Paginated<T> {
private final List<T> content;
public Paginated(Collection<T> content) {
this.content = ImmutableList.copyOf(content);
}
public List<T> getContent() {
return this.content;
}
public int getMaxPages(int entriesPerPage) {
return (int) Math.ceil((double) this.content.size() / (double) entriesPerPage);
}
public List<Entry<T>> getPage(int pageNo, int pageSize) {
if (pageNo < 1) {
throw new IllegalArgumentException("pageNo cannot be less than 1: " + pageNo);
}
int first = (pageNo - 1) * pageSize;
if (this.content.size() <= first) {
throw new IllegalStateException("Content does not contain that many elements. (requested page: " + pageNo +
", page size: " + pageSize + ", page first index: " + first + ", content size: " + this.content.size() + ")");
}
int last = first + pageSize - 1;
List<Entry<T>> out = new ArrayList<>(pageSize);
for (int i = first; i <= last && i < this.content.size(); i++) {
out.add(new Entry<>(i + 1, this.content.get(i)));
}
return out;
}
public static final class Entry<T> {
private final int position;
private final T value;
public Entry(int position, T value) {
this.position = position;
this.value = value;
}
public int position() {
return this.position;
}
public T value() {
return this.value;
}
@Override
public String toString() {
return this.position + ": " + this.value;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Entry)) return false;
Entry<?> entry = (Entry<?>) o;
return this.position == entry.position && Objects.equals(this.value, entry.value);
}
@Override
public int hashCode() {
return Objects.hash(this.position, this.value);
}
}
}

View File

@@ -29,7 +29,6 @@ import me.lucko.luckperms.common.bulkupdate.action.BulkUpdateAction;
import me.lucko.luckperms.common.bulkupdate.action.DeleteAction;
import me.lucko.luckperms.common.bulkupdate.action.UpdateAction;
import me.lucko.luckperms.common.filter.Comparison;
import me.lucko.luckperms.common.filter.Constraint;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;

View File

@@ -0,0 +1,50 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.filter;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class PageParametersTest {
@ParameterizedTest(name = "[{index}] {0} {1}")
@CsvSource({
"5, 150, 30",
"151, 150, 1",
"150, 150, 1",
"149, 150, 2",
"1, 1, 1",
"1, 0, 0",
"10, 0, 0",
})
public void testMaxPage(int pageSize, int total, int expectedMaxPage) {
int maxPage = new PageParameters(pageSize, 1).getMaxPage(total);
assertEquals(expectedMaxPage, maxPage);
}
}

View File

@@ -27,14 +27,13 @@ package me.lucko.luckperms.common.storage;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.config.LuckPermsConfiguration;
import me.lucko.luckperms.common.event.EventDispatcher;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PrimaryGroupHolder;
import me.lucko.luckperms.common.model.User;
@@ -57,13 +56,13 @@ import net.luckperms.api.node.types.InheritanceNode;
import net.luckperms.api.node.types.PermissionNode;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.Instant;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -121,24 +120,6 @@ public abstract class AbstractStorageTest {
@Test
public void testActionLog() throws Exception {
LoggedAction action = LoggedAction.build()
.source(UUID.randomUUID())
.sourceName("Test Source")
.targetType(Action.Target.Type.USER)
.target(UUID.randomUUID())
.targetName("Test Target")
.description("hello 123 hello 123")
.build();
this.storage.logAction(action);
Log log = this.storage.getLog();
assertEquals(1, log.getContent().size());
assertEquals(action, log.getContent().first());
}
@Test
public void testActionLogPage() throws Exception {
UUID sourceUuid = UUID.randomUUID();
UUID targetUuid = UUID.randomUUID();
@@ -192,7 +173,9 @@ public abstract class AbstractStorageTest {
mockAction.apply(92),
mockAction.apply(90)
), page.getContent());
List<Integer> positions = page.getNumberedContent().stream().map(LogPage.Entry::position).collect(Collectors.toList());
assertEquals(ImmutableList.of(1, 2, 3, 4, 5), positions);
assertEquals(150, page.getTotalEntries());
page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(5, 3));
assertEquals(ImmutableList.of(
@@ -202,15 +185,28 @@ public abstract class AbstractStorageTest {
mockAction.apply(72),
mockAction.apply(70)
), page.getContent());
positions = page.getNumberedContent().stream().map(LogPage.Entry::position).collect(Collectors.toList());
assertEquals(ImmutableList.of(11, 12, 13, 14, 15), positions);
assertEquals(150, page.getTotalEntries());
page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(5, 31));
assertEquals(150, page.getTotalEntries());
assertEquals(0, page.getContent().size());
page = this.storage.getLogPage(ActionFilters.source(sourceUuid), new PageParameters(500, 1));
assertEquals(150, page.getTotalEntries());
assertEquals(150, page.getContent().size());
page = this.storage.getLogPage(ActionFilters.all(), new PageParameters(500, 1));
page = this.storage.getLogPage(ActionFilters.source(sourceUuid), null);
assertEquals(150, page.getTotalEntries());
assertEquals(150, page.getContent().size());
page = this.storage.getLogPage(ActionFilters.all(), null);
assertEquals(320, page.getTotalEntries());
assertEquals(320, page.getContent().size());
page = this.storage.getLogPage(ActionFilters.user(targetUuid), new PageParameters(500, 1));
assertEquals(300, page.getContent().size());
page = this.storage.getLogPage(ActionFilters.user(targetUuid), new PageParameters(5, 1));
assertEquals(300, page.getTotalEntries());
page = this.storage.getLogPage(ActionFilters.group("test_group"), new PageParameters(10, 1));
assertEquals(5, page.getContent().size());

View File

@@ -8,7 +8,7 @@ import org.junit.jupiter.api.Tag;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;
//@Tag("docker")
@Tag("docker")
public class MongoStorageTest extends AbstractStorageTest {
private final GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("mongo"))

View File

@@ -1,104 +0,0 @@
/*
* This file is part of LuckPerms, licensed under the MIT License.
*
* Copyright (c) lucko (Luck) <luck@lucko.me>
* 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.util;
import com.google.common.collect.ImmutableList;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.List;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class PaginatedTest {
private static final Paginated<String> EXAMPLE_PAGE = new Paginated<>(ImmutableList.of("one", "two", "three", "four", "five"));
@ParameterizedTest
@CsvSource({
"3, 2",
"1, 5",
"1, 6"
})
public void testMaxPages(int expected, int entriesPerPage) {
assertEquals(expected, EXAMPLE_PAGE.getMaxPages(entriesPerPage));
}
@ParameterizedTest
@CsvSource({
"1, 2",
"2, 2",
"3, 1"
})
public void testPageSize(int pageNo, int expectedSize) {
List<Paginated.Entry<String>> page = EXAMPLE_PAGE.getPage(pageNo, 2);
assertEquals(expectedSize, page.size());
}
private static Stream<Arguments> testPageContent() {
return Stream.of(
Arguments.of(1, ImmutableList.of(
new Paginated.Entry<>(1, "one"),
new Paginated.Entry<>(2, "two")
)),
Arguments.of(2, ImmutableList.of(
new Paginated.Entry<>(3, "three"),
new Paginated.Entry<>(4, "four")
)),
Arguments.of(3, ImmutableList.of(
new Paginated.Entry<>(5, "five")
))
);
}
@ParameterizedTest
@MethodSource
public void testPageContent(int pageNo, List<Paginated.Entry<String>> expectedContent) {
assertEquals(expectedContent, EXAMPLE_PAGE.getPage(pageNo, 2));
}
@ParameterizedTest
@CsvSource({
"4, 2",
})
public void testFailState(int pageNo, int pageSize) {
assertThrows(IllegalStateException.class, () -> EXAMPLE_PAGE.getPage(pageNo, pageSize));
}
@ParameterizedTest
@CsvSource({
"0, 2",
"-1, 2"
})
public void testFailArgument(int pageNo, int pageSize) {
assertThrows(IllegalArgumentException.class, () -> EXAMPLE_PAGE.getPage(pageNo, pageSize));
}
}

View File

@@ -44,7 +44,6 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerLoginNetworkHandler;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Uuids;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

View File

@@ -29,8 +29,6 @@ import com.google.common.collect.Iterables;
import me.lucko.luckperms.common.messaging.pluginmsg.AbstractPluginMessageMessenger;
import me.lucko.luckperms.common.plugin.scheduler.SchedulerTask;
import me.lucko.luckperms.fabric.LPFabricPlugin;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.luckperms.api.messenger.IncomingMessageConsumer;
@@ -39,7 +37,6 @@ import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.packet.CustomPayload;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.Identifier;

View File

@@ -32,8 +32,6 @@ import net.luckperms.api.query.QueryOptions;
import net.luckperms.api.util.Tristate;
import net.minecraft.server.network.ServerPlayerEntity;
import java.util.Locale;
/**
* Mixin interface for {@link ServerPlayerEntity} implementing {@link User} related
* caches and functions.

View File

@@ -28,7 +28,6 @@ package me.lucko.luckperms.standalone.app.integration;
import me.lucko.luckperms.standalone.app.LuckPermsApplication;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.ansi.ANSIComponentSerializer;
import net.kyori.ansi.ColorLevel;
import java.util.Set;
import java.util.UUID;

View File

@@ -28,8 +28,10 @@ package me.lucko.luckperms.standalone;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.filter.FilterList;
import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User;
@@ -182,7 +184,7 @@ public class StorageIntegrationTest {
assertNotNull(testTrack);
assertEquals(ImmutableList.of("default", "test"), track.getGroups());
Log actionLog = plugin.getStorage().getLog().join();
LogPage actionLog = plugin.getStorage().getLogPage(FilterList.empty(), new PageParameters(1000, 1)).join();
assertTrue(actionLog.getContent().contains(exampleLogEntry));
List<NodeEntry<String, Node>> groupSearchResult = plugin.getStorage().searchGroupNodes(StandardNodeMatchers.key(TEST_PERMISSION_1)).join();