From 5ecbc473e986015f57cd1c90d8a97201de20367a Mon Sep 17 00:00:00 2001
From: Luck
Date: Thu, 13 Jun 2024 20:31:36 +0100
Subject: [PATCH] Add API methods and command tests for new ActionLog system
---
.../java/net/luckperms/api/LuckPerms.java | 11 +
.../net/luckperms/api/actionlog/Action.java | 8 +-
.../luckperms/api/actionlog/ActionLog.java | 5 +
.../luckperms/api/actionlog/ActionLogger.java | 67 ++++--
.../api/actionlog/filter/ActionFilter.java | 114 ++++++++++
.../actionlog/filter/ActionFilterFactory.java | 88 ++++++++
.../api/actionlog/filter/package-info.java | 29 +++
.../java/net/luckperms/api/util/Page.java | 53 +++++
.../common/actionlog/LogDispatcher.java | 68 +++---
.../common/actionlog/LoggedAction.java | 15 +-
.../common/api/LuckPermsApiProvider.java | 6 +
.../api/implementation/ApiActionFilter.java | 47 ++++
.../ApiActionFilterFactory.java | 77 +++++++
.../api/implementation/ApiActionLog.java | 1 +
.../api/implementation/ApiActionLogger.java | 57 ++++-
.../common/bulkupdate/BulkUpdateField.java | 25 +++
.../bulkupdate/BulkUpdateSqlBuilder.java | 4 -
.../common/commands/log/LogGroupHistory.java | 4 +-
.../common/commands/log/LogRecent.java | 2 +-
.../common/commands/log/LogSearch.java | 4 +-
.../common/commands/log/LogTrackHistory.java | 4 +-
.../common/commands/log/LogUserHistory.java | 4 +-
.../luckperms/common/config/ConfigKeys.java | 5 +
.../common/filter/ConstraintFactory.java | 25 +++
.../luckperms/common/filter/FilterList.java | 25 +++
.../filter/sql/ConstraintSqlBuilder.java | 25 +++
.../messaging/InternalMessagingService.java | 10 +-
.../messaging/LuckPermsMessagingService.java | 23 +-
.../common/sender/AbstractSender.java | 6 +-
.../common/sender/SenderFactory.java | 4 +-
.../luckperms/common/storage/Storage.java | 33 +--
.../implementation/file/FileActionLogger.java | 15 +-
.../implementation/mongodb/MongoStorage.java | 2 +-
.../implementation/sql/SqlStorage.java | 2 +-
.../luckperms/common/util/AsyncInterface.java | 71 ++++++
.../actionlog/ActionFilterMongoTest.java | 12 +-
.../common/storage/AbstractStorageTest.java | 10 +
.../storage/ConfigurateStorageTest.java | 25 +++
.../common/storage/MongoStorageTest.java | 25 +++
.../app/integration/CommandExecutor.java | 12 +-
.../app/integration/StandaloneSender.java | 48 +++++
...ngletonPlayer.java => StandaloneUser.java} | 54 ++---
.../standalone/LPStandalonePlugin.java | 4 +-
.../standalone/StandaloneCommandManager.java | 10 +-
.../standalone/StandaloneSenderFactory.java | 45 ++--
.../stub/StandaloneContextManager.java | 24 ++-
.../standalone/CommandsIntegrationTest.java | 204 +++++++++++++++---
.../standalone/WebEditorIntegrationTest.java | 4 +-
.../standalone/utils/CommandTester.java | 48 +++--
.../standalone/utils/TestPluginBootstrap.java | 70 ++----
.../standalone/utils/TestSender.java | 113 ++++++++++
51 files changed, 1347 insertions(+), 300 deletions(-)
create mode 100644 api/src/main/java/net/luckperms/api/actionlog/filter/ActionFilter.java
create mode 100644 api/src/main/java/net/luckperms/api/actionlog/filter/ActionFilterFactory.java
create mode 100644 api/src/main/java/net/luckperms/api/actionlog/filter/package-info.java
create mode 100644 api/src/main/java/net/luckperms/api/util/Page.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionFilter.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionFilterFactory.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/util/AsyncInterface.java
create mode 100644 standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/StandaloneSender.java
rename standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/{SingletonPlayer.java => StandaloneUser.java} (57%)
create mode 100644 standalone/src/test/java/me/lucko/luckperms/standalone/utils/TestSender.java
diff --git a/api/src/main/java/net/luckperms/api/LuckPerms.java b/api/src/main/java/net/luckperms/api/LuckPerms.java
index 8e99fe610..6c851c45c 100644
--- a/api/src/main/java/net/luckperms/api/LuckPerms.java
+++ b/api/src/main/java/net/luckperms/api/LuckPerms.java
@@ -26,6 +26,7 @@
package net.luckperms.api;
import net.luckperms.api.actionlog.ActionLogger;
+import net.luckperms.api.actionlog.filter.ActionFilterFactory;
import net.luckperms.api.context.ContextCalculator;
import net.luckperms.api.context.ContextManager;
import net.luckperms.api.event.EventBus;
@@ -267,4 +268,14 @@ public interface LuckPerms {
@Internal
@NonNull NodeMatcherFactory getNodeMatcherFactory();
+ /**
+ * Gets the {@link ActionFilterFactory}.
+ *
+ * @return the action filter factory
+ * @since 5.5
+ */
+ @Internal
+ @NonNull
+ ActionFilterFactory getActionFilterFactory();
+
}
diff --git a/api/src/main/java/net/luckperms/api/actionlog/Action.java b/api/src/main/java/net/luckperms/api/actionlog/Action.java
index 82d3f2a5a..53260674c 100644
--- a/api/src/main/java/net/luckperms/api/actionlog/Action.java
+++ b/api/src/main/java/net/luckperms/api/actionlog/Action.java
@@ -28,6 +28,7 @@ package net.luckperms.api.actionlog;
import net.luckperms.api.LuckPermsProvider;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
+import org.jetbrains.annotations.ApiStatus.NonExtendable;
import java.time.Instant;
import java.util.Optional;
@@ -35,7 +36,10 @@ import java.util.UUID;
/**
* Represents a logged action.
+ *
+ * API users should not implement this interface directly.
*/
+@NonExtendable
public interface Action extends Comparable {
/**
@@ -81,6 +85,7 @@ public interface Action extends Comparable {
/**
* Represents the source of an action.
*/
+ @NonExtendable
interface Source {
/**
@@ -102,6 +107,7 @@ public interface Action extends Comparable {
/**
* Represents the target of an action.
*/
+ @NonExtendable
interface Target {
/**
@@ -126,7 +132,7 @@ public interface Action extends Comparable {
@NonNull Type getType();
/**
- * Represents the type of a {@link Target}.
+ * Represents the type of {@link Target}.
*/
enum Type {
USER, GROUP, TRACK
diff --git a/api/src/main/java/net/luckperms/api/actionlog/ActionLog.java b/api/src/main/java/net/luckperms/api/actionlog/ActionLog.java
index bba6eb457..131ab3a5c 100644
--- a/api/src/main/java/net/luckperms/api/actionlog/ActionLog.java
+++ b/api/src/main/java/net/luckperms/api/actionlog/ActionLog.java
@@ -25,6 +25,7 @@
package net.luckperms.api.actionlog;
+import net.luckperms.api.actionlog.filter.ActionFilter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Unmodifiable;
@@ -40,7 +41,11 @@ import java.util.UUID;
* You can add to the log using the {@link ActionLogger}, and then request an updated copy.
*
* All methods are thread safe, and return immutable and thread safe collections.
+ *
+ * @deprecated Use {@link ActionLogger#queryActions(ActionFilter)} or
+ * {@link ActionLogger#queryActions(ActionFilter, int, int)} instead.
*/
+@Deprecated
public interface ActionLog {
/**
diff --git a/api/src/main/java/net/luckperms/api/actionlog/ActionLogger.java b/api/src/main/java/net/luckperms/api/actionlog/ActionLogger.java
index 0f4bf7878..8b8eb6dca 100644
--- a/api/src/main/java/net/luckperms/api/actionlog/ActionLogger.java
+++ b/api/src/main/java/net/luckperms/api/actionlog/ActionLogger.java
@@ -25,9 +25,11 @@
package net.luckperms.api.actionlog;
-import net.luckperms.api.messaging.MessagingService;
+import net.luckperms.api.actionlog.filter.ActionFilter;
+import net.luckperms.api.util.Page;
import org.checkerframework.checker.nullness.qual.NonNull;
+import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
@@ -46,43 +48,78 @@ public interface ActionLogger {
* Gets a {@link ActionLog} instance from the plugin storage.
*
* @return a log instance
+ * @deprecated Use {@link #queryActions(ActionFilter)} or {@link #queryActions(ActionFilter, int, int)} instead. These methods
+ * are more efficient (they don't load the full action log into memory) and allow for pagination.
*/
+ @Deprecated
@NonNull CompletableFuture getLog();
/**
- * Submits a log entry to the plugin to be handled.
+ * Gets all actions from the action log matching the given {@code filter}.
*
- * This method submits the log to the storage provider and broadcasts
- * it.
+ * If the filter is {@code null}, all actions will be returned.
*
- * It is therefore roughly equivalent to calling
- * {@link #submitToStorage(Action)} and {@link #broadcastAction(Action)},
- * however, using this method is preferred to making the calls individually.
+ * Unlike {@link #queryActions(ActionFilter, int, int)}, this method does not implement any pagination and will return
+ * all entries at once.
*
- * If you want to submit a log entry but don't know which method to pick,
+ * @param filter the filter, optional
+ * @return the actions
+ * @since 5.5
+ */
+ @NonNull CompletableFuture> queryActions(@NonNull ActionFilter filter);
+
+ /**
+ * Gets a page of actions from the action log matching the given {@code filter}.
+ *
+ * If the filter is {@code null}, all actions will be returned.
+ *
+ * @param filter the filter, optional
+ * @param pageSize the size of the page
+ * @param pageNumber the page number
+ * @return the page of actions
+ * @since 5.5
+ */
+ @NonNull CompletableFuture> queryActions(@NonNull ActionFilter filter, int pageSize, int pageNumber);
+
+ /**
+ * Submits a logged action to LuckPerms.
+ *
+ * This method submits the action to the storage provider to be persisted in the action log.
+ * It also broadcasts it to administrator players on the current instance and to admins on other
+ * connected servers if a messaging service is configured.
+ *
+ * It is roughly equivalent to calling
+ * {@link #submitToStorage(Action)} followed by {@link #broadcastAction(Action)},
+ * however using this method is preferred to making the calls individually.
+ *
+ * If you want to submit an action log entry but don't know which method to pick,
* use this one.
*
* @param entry the entry to submit
- * @return a future which will complete when the action is done
+ * @return a future which will complete when the action is submitted
*/
@NonNull CompletableFuture submit(@NonNull Action entry);
/**
- * Submits a log entry to the plugins storage handler.
+ * Submits a logged action to LuckPerms and persists it in the storage backend.
+ *
+ * This method does not broadcast the action or send it through the messaging service.
*
* @param entry the entry to submit
- * @return a future which will complete when the action is done
+ * @return a future which will complete when the action is submitted
*/
@NonNull CompletableFuture submitToStorage(@NonNull Action entry);
/**
- * Submits a log entry to the plugins log broadcasting handler.
+ * Submits a logged action to LuckPerms and broadcasts it to administrators.
*
- * If enabled, this method will also dispatch the log entry via the
- * plugins {@link MessagingService}.
+ * The broadcast is made to administrator players on the current instance
+ * and to admins on other connected servers if a messaging service is configured.
+ *
+ * This method does not save the action to the plugin storage backend.
*
* @param entry the entry to submit
- * @return a future which will complete when the action is done
+ * @return a future which will complete when the action is broadcasted
*/
@NonNull CompletableFuture broadcastAction(@NonNull Action entry);
diff --git a/api/src/main/java/net/luckperms/api/actionlog/filter/ActionFilter.java b/api/src/main/java/net/luckperms/api/actionlog/filter/ActionFilter.java
new file mode 100644
index 000000000..6614cbb34
--- /dev/null
+++ b/api/src/main/java/net/luckperms/api/actionlog/filter/ActionFilter.java
@@ -0,0 +1,114 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package net.luckperms.api.actionlog.filter;
+
+import net.luckperms.api.LuckPermsProvider;
+import net.luckperms.api.actionlog.Action;
+import org.jetbrains.annotations.ApiStatus.NonExtendable;
+
+import java.util.UUID;
+import java.util.function.Predicate;
+
+/**
+ * A predicate filter which matches certain {@link Action}s.
+ *
+ * API users should not implement this interface directly.
+ *
+ * @since 5.5
+ */
+@NonExtendable
+public interface ActionFilter extends Predicate {
+
+ /**
+ * Gets an {@link ActionFilter} which matches any action.
+ *
+ * @return the matcher
+ */
+ static ActionFilter any() {
+ return LuckPermsProvider.get().getActionFilterFactory().any();
+ }
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions with a specific source user.
+ *
+ * @param uniqueId the source user unique id
+ * @return the matcher
+ */
+ static ActionFilter source(UUID uniqueId) {
+ return LuckPermsProvider.get().getActionFilterFactory().source(uniqueId);
+ }
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions which target a specific user.
+ *
+ * @param uniqueId the target user unique id
+ * @return the matcher
+ */
+ static ActionFilter user(UUID uniqueId) {
+ return LuckPermsProvider.get().getActionFilterFactory().user(uniqueId);
+ }
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions which target a specific group.
+ *
+ * @param name the target group name
+ * @return the matcher
+ */
+ static ActionFilter group(String name) {
+ return LuckPermsProvider.get().getActionFilterFactory().group(name);
+ }
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions which target a specific track.
+ *
+ * @param name the target track name
+ * @return the matcher
+ */
+ static ActionFilter track(String name) {
+ return LuckPermsProvider.get().getActionFilterFactory().track(name);
+ }
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions which contain a specific search query in the source name,
+ * target name or description.
+ *
+ * @param query the search query
+ * @return the matcher
+ */
+ static ActionFilter search(String query) {
+ return LuckPermsProvider.get().getActionFilterFactory().search(query);
+ }
+
+ /**
+ * Tests to see if the given {@link Action} matches the filter.
+ *
+ * @param action the action to test
+ * @return true if the action matched
+ */
+ @Override
+ boolean test(Action action);
+
+}
diff --git a/api/src/main/java/net/luckperms/api/actionlog/filter/ActionFilterFactory.java b/api/src/main/java/net/luckperms/api/actionlog/filter/ActionFilterFactory.java
new file mode 100644
index 000000000..31e699ac5
--- /dev/null
+++ b/api/src/main/java/net/luckperms/api/actionlog/filter/ActionFilterFactory.java
@@ -0,0 +1,88 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package net.luckperms.api.actionlog.filter;
+
+import org.jetbrains.annotations.ApiStatus.Internal;
+
+import java.util.UUID;
+
+/**
+ * A factory which creates {@link ActionFilter}s.
+ *
+ * @since 5.5
+ */
+@Internal
+public interface ActionFilterFactory {
+
+ /**
+ * Gets an {@link ActionFilter} which matches any action.
+ *
+ * @return the matcher
+ */
+ ActionFilter any();
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions with a specific source user.
+ *
+ * @param uniqueId the source user unique id
+ * @return the matcher
+ */
+ ActionFilter source(UUID uniqueId);
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions which target a specific user.
+ *
+ * @param uniqueId the target user unique id
+ * @return the matcher
+ */
+ ActionFilter user(UUID uniqueId);
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions which target a specific group.
+ *
+ * @param name the target group name
+ * @return the matcher
+ */
+ ActionFilter group(String name);
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions which target a specific track.
+ *
+ * @param name the target track name
+ * @return the matcher
+ */
+ ActionFilter track(String name);
+
+ /**
+ * Gets an {@link ActionFilter} which matches actions which contain a specific search query in the source name,
+ * target name or description.
+ *
+ * @param query the search query
+ * @return the matcher
+ */
+ ActionFilter search(String query);
+
+}
diff --git a/api/src/main/java/net/luckperms/api/actionlog/filter/package-info.java b/api/src/main/java/net/luckperms/api/actionlog/filter/package-info.java
new file mode 100644
index 000000000..2eebf3be8
--- /dev/null
+++ b/api/src/main/java/net/luckperms/api/actionlog/filter/package-info.java
@@ -0,0 +1,29 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * {@link net.luckperms.api.actionlog.Action} filters.
+ */
+package net.luckperms.api.actionlog.filter;
\ No newline at end of file
diff --git a/api/src/main/java/net/luckperms/api/util/Page.java b/api/src/main/java/net/luckperms/api/util/Page.java
new file mode 100644
index 000000000..3ecf589c4
--- /dev/null
+++ b/api/src/main/java/net/luckperms/api/util/Page.java
@@ -0,0 +1,53 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package net.luckperms.api.util;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+
+import java.util.List;
+
+/**
+ * Represents a page of entries.
+ *
+ * @since 5.5
+ */
+public interface Page {
+
+ /**
+ * Gets the entries on this page.
+ *
+ * @return the entries
+ */
+ @NonNull List entries();
+
+ /**
+ * Gets the total/overall number of entries (not just the number of entries on this page).
+ *
+ * @return the total number of entries
+ */
+ int overallSize();
+
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java
index c4ffd5b45..befa7ab2a 100644
--- a/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java
+++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/LogDispatcher.java
@@ -29,12 +29,14 @@ import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.commands.log.LogNotify;
import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.locale.Message;
+import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import net.luckperms.api.event.log.LogBroadcastEvent;
import net.luckperms.api.event.log.LogNotifyEvent;
import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
public class LogDispatcher {
@@ -64,7 +66,12 @@ public class LogDispatcher {
return !this.plugin.getEventDispatcher().dispatchLogBroadcast(cancelled, entry, origin);
}
- private void broadcast(LoggedAction entry, LogNotifyEvent.Origin origin, Sender sender) {
+ // broadcast the entry to online players
+ private void broadcast(LoggedAction entry, LogBroadcastEvent.Origin broadcastOrigin, LogNotifyEvent.Origin origin, Sender sender) {
+ if (!shouldBroadcast(entry, broadcastOrigin)) {
+ return;
+ }
+
this.plugin.getOnlineSenders()
.filter(CommandPermission.LOG_NOTIFY::isAuthorized)
.filter(s -> {
@@ -74,41 +81,46 @@ public class LogDispatcher {
.forEach(s -> Message.LOG.send(s, entry));
}
- public void dispatch(LoggedAction entry, Sender sender) {
+ // log the entry to storage
+ public CompletableFuture logToStorage(LoggedAction entry) {
if (!this.plugin.getEventDispatcher().dispatchLogPublish(false, entry)) {
- this.plugin.getStorage().logAction(entry);
+ return this.plugin.getStorage().logAction(entry);
+ } else {
+ return CompletableFuture.completedFuture(null);
}
+ }
- this.plugin.getMessagingService().ifPresent(service -> service.pushLog(entry));
-
- if (shouldBroadcast(entry, LogBroadcastEvent.Origin.LOCAL)) {
- broadcast(entry, LogNotifyEvent.Origin.LOCAL, sender);
+ // log the entry to messaging
+ public CompletableFuture logToMessaging(LoggedAction entry) {
+ InternalMessagingService messagingService = this.plugin.getMessagingService().orElse(null);
+ if (messagingService != null) {
+ return messagingService.pushLog(entry);
+ } else {
+ return CompletableFuture.completedFuture(null);
}
}
+ // log the entry to storage and messaging, and broadcast it to online players
+ private CompletableFuture dispatch(LoggedAction entry, Sender sender, LogBroadcastEvent.Origin broadcastOrigin, LogNotifyEvent.Origin origin) {
+ CompletableFuture storageFuture = logToStorage(entry);
+ CompletableFuture messagingFuture = logToMessaging(entry);
+ broadcast(entry, broadcastOrigin, origin, sender);
+ return CompletableFuture.allOf(storageFuture, messagingFuture);
+ }
+
+ public CompletableFuture dispatch(LoggedAction entry, Sender sender) {
+ return dispatch(entry, sender, LogBroadcastEvent.Origin.LOCAL, LogNotifyEvent.Origin.LOCAL);
+ }
+
+ public CompletableFuture dispatchFromApi(LoggedAction entry) {
+ return dispatch(entry, null, LogBroadcastEvent.Origin.LOCAL_API, LogNotifyEvent.Origin.LOCAL_API);
+ }
+
public void broadcastFromApi(LoggedAction entry) {
- this.plugin.getMessagingService().ifPresent(extendedMessagingService -> extendedMessagingService.pushLog(entry));
-
- if (shouldBroadcast(entry, LogBroadcastEvent.Origin.LOCAL_API)) {
- broadcast(entry, LogNotifyEvent.Origin.LOCAL_API, null);
- }
+ broadcast(entry, LogBroadcastEvent.Origin.LOCAL_API, LogNotifyEvent.Origin.LOCAL_API, null);
}
- public void dispatchFromApi(LoggedAction entry) {
- if (!this.plugin.getEventDispatcher().dispatchLogPublish(false, entry)) {
- try {
- this.plugin.getStorage().logAction(entry).get();
- } catch (Exception e) {
- this.plugin.getLogger().warn("Error whilst storing action", e);
- }
- }
-
- broadcastFromApi(entry);
- }
-
- public void dispatchFromRemote(LoggedAction entry) {
- if (shouldBroadcast(entry, LogBroadcastEvent.Origin.REMOTE)) {
- broadcast(entry, LogNotifyEvent.Origin.REMOTE, null);
- }
+ public void broadcastFromRemote(LoggedAction entry) {
+ broadcast(entry, LogBroadcastEvent.Origin.REMOTE, LogNotifyEvent.Origin.REMOTE, null);
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/LoggedAction.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/LoggedAction.java
index 0d04c0eac..00ce2c64d 100644
--- a/common/src/main/java/me/lucko/luckperms/common/actionlog/LoggedAction.java
+++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/LoggedAction.java
@@ -26,6 +26,7 @@
package me.lucko.luckperms.common.actionlog;
import com.google.common.base.Strings;
+import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.model.PermissionHolder;
@@ -44,10 +45,10 @@ import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
-import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
/**
* An implementation of {@link Action} and {@link Action.Builder},
@@ -123,15 +124,11 @@ public class LoggedAction implements Action {
return ActionComparator.INSTANCE.compare(this, other);
}
- public boolean matchesSearch(String query) {
- query = Objects.requireNonNull(query, "query").toLowerCase(Locale.ROOT);
- return this.source.name.toLowerCase(Locale.ROOT).contains(query) ||
- this.target.name.toLowerCase(Locale.ROOT).contains(query) ||
- this.description.toLowerCase(Locale.ROOT).contains(query);
- }
-
public void submit(LuckPermsPlugin plugin, Sender sender) {
- plugin.getLogDispatcher().dispatch(this, sender);
+ CompletableFuture future = plugin.getLogDispatcher().dispatch(this, sender);
+ if (plugin.getConfiguration().get(ConfigKeys.LOG_SYNCHRONOUSLY_IN_COMMANDS)) {
+ future.join();
+ }
}
@Override
diff --git a/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java b/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java
index 7da93b90e..a68ef671a 100644
--- a/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java
+++ b/common/src/main/java/me/lucko/luckperms/common/api/LuckPermsApiProvider.java
@@ -25,6 +25,7 @@
package me.lucko.luckperms.common.api;
+import me.lucko.luckperms.common.api.implementation.ApiActionFilterFactory;
import me.lucko.luckperms.common.api.implementation.ApiActionLogger;
import me.lucko.luckperms.common.api.implementation.ApiContextManager;
import me.lucko.luckperms.common.api.implementation.ApiGroupManager;
@@ -47,6 +48,7 @@ import me.lucko.luckperms.common.plugin.logging.PluginLogger;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.actionlog.ActionLogger;
+import net.luckperms.api.actionlog.filter.ActionFilterFactory;
import net.luckperms.api.context.ContextManager;
import net.luckperms.api.messaging.MessagingService;
import net.luckperms.api.messenger.MessengerProvider;
@@ -225,4 +227,8 @@ public class LuckPermsApiProvider implements LuckPerms {
return ApiNodeMatcherFactory.INSTANCE;
}
+ @Override
+ public @NonNull ActionFilterFactory getActionFilterFactory() {
+ return ApiActionFilterFactory.INSTANCE;
+ }
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionFilter.java b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionFilter.java
new file mode 100644
index 000000000..65a4be9ea
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionFilter.java
@@ -0,0 +1,47 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.lucko.luckperms.common.api.implementation;
+
+import me.lucko.luckperms.common.filter.FilterList;
+import net.luckperms.api.actionlog.Action;
+import net.luckperms.api.actionlog.filter.ActionFilter;
+
+public class ApiActionFilter implements ActionFilter {
+ private final FilterList filter;
+
+ public ApiActionFilter(FilterList filter) {
+ this.filter = filter;
+ }
+
+ @Override
+ public boolean test(Action action) {
+ return this.filter.evaluate(action);
+ }
+
+ public FilterList getFilter() {
+ return this.filter;
+ }
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionFilterFactory.java b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionFilterFactory.java
new file mode 100644
index 000000000..5bd9a60c6
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionFilterFactory.java
@@ -0,0 +1,77 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.lucko.luckperms.common.api.implementation;
+
+import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
+import net.luckperms.api.actionlog.filter.ActionFilter;
+import net.luckperms.api.actionlog.filter.ActionFilterFactory;
+
+import java.util.Objects;
+import java.util.UUID;
+
+public final class ApiActionFilterFactory implements ActionFilterFactory {
+ public static final ApiActionFilterFactory INSTANCE = new ApiActionFilterFactory();
+
+ private ApiActionFilterFactory() {
+
+ }
+
+ @Override
+ public ActionFilter any() {
+ return new ApiActionFilter(ActionFilters.all());
+ }
+
+ @Override
+ public ActionFilter source(UUID uniqueId) {
+ Objects.requireNonNull(uniqueId, "uniqueId");
+ return new ApiActionFilter(ActionFilters.source(uniqueId));
+ }
+
+ @Override
+ public ActionFilter user(UUID uniqueId) {
+ Objects.requireNonNull(uniqueId, "uniqueId");
+ return new ApiActionFilter(ActionFilters.user(uniqueId));
+ }
+
+ @Override
+ public ActionFilter group(String name) {
+ Objects.requireNonNull(name, "name");
+ return new ApiActionFilter(ActionFilters.group(name));
+ }
+
+ @Override
+ public ActionFilter track(String name) {
+ Objects.requireNonNull(name, "name");
+ return new ApiActionFilter(ActionFilters.track(name));
+ }
+
+ @Override
+ public ActionFilter search(String query) {
+ Objects.requireNonNull(query, "query");
+ return new ApiActionFilter(ActionFilters.search(query));
+ }
+
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionLog.java b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionLog.java
index 40f1c0e6a..ef8e7df79 100644
--- a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionLog.java
+++ b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionLog.java
@@ -37,6 +37,7 @@ import java.util.Objects;
import java.util.SortedSet;
import java.util.UUID;
+@Deprecated
public class ApiActionLog implements ActionLog {
private final SortedSet content;
diff --git a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionLogger.java b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionLogger.java
index 67d219282..c571d5e04 100644
--- a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionLogger.java
+++ b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiActionLogger.java
@@ -25,14 +25,22 @@
package me.lucko.luckperms.common.api.implementation;
+import me.lucko.luckperms.common.actionlog.LogDispatcher;
+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.filter.FilterList;
+import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import net.luckperms.api.actionlog.Action;
import net.luckperms.api.actionlog.ActionLog;
import net.luckperms.api.actionlog.ActionLogger;
+import net.luckperms.api.actionlog.filter.ActionFilter;
+import net.luckperms.api.util.Page;
import org.checkerframework.checker.nullness.qual.NonNull;
+import java.util.List;
+import java.util.Objects;
import java.util.concurrent.CompletableFuture;
public class ApiActionLogger implements ActionLogger {
@@ -48,23 +56,66 @@ public class ApiActionLogger implements ActionLogger {
}
@Override
+ @Deprecated
public @NonNull CompletableFuture getLog() {
return this.plugin.getStorage().getLogPage(ActionFilters.all(), null)
.thenApply(result -> new ApiActionLog(result.getContent()));
}
+ @Override
+ public @NonNull CompletableFuture> queryActions(@NonNull ActionFilter filter) {
+ return this.plugin.getStorage().getLogPage(getFilterList(filter), null).thenApply(ActionPage::new).thenApply(Page::entries);
+ }
+
+ @Override
+ public @NonNull CompletableFuture> queryActions(@NonNull ActionFilter filter, int pageSize, int pageNumber) {
+ return this.plugin.getStorage().getLogPage(getFilterList(filter), new PageParameters(pageSize, pageNumber)).thenApply(ActionPage::new);
+ }
+
@Override
public @NonNull CompletableFuture submit(@NonNull Action entry) {
- return CompletableFuture.runAsync(() -> this.plugin.getLogDispatcher().dispatchFromApi((LoggedAction) entry), this.plugin.getBootstrap().getScheduler().async());
+ return this.plugin.getLogDispatcher().dispatchFromApi((LoggedAction) entry);
}
@Override
public @NonNull CompletableFuture submitToStorage(@NonNull Action entry) {
- return this.plugin.getStorage().logAction(entry);
+ return this.plugin.getLogDispatcher().logToStorage((LoggedAction) entry);
}
@Override
public @NonNull CompletableFuture broadcastAction(@NonNull Action entry) {
- return CompletableFuture.runAsync(() -> this.plugin.getLogDispatcher().broadcastFromApi((LoggedAction) entry), this.plugin.getBootstrap().getScheduler().async());
+ LogDispatcher dispatcher = this.plugin.getLogDispatcher();
+
+ CompletableFuture messagingFuture = dispatcher.logToStorage(((LoggedAction) entry));
+ dispatcher.broadcastFromApi(((LoggedAction) entry));
+ return messagingFuture;
+ }
+
+ private static FilterList getFilterList(ActionFilter filter) {
+ Objects.requireNonNull(filter, "filter");
+ if (filter instanceof ApiActionFilter) {
+ return ((ApiActionFilter) filter).getFilter();
+ } else {
+ throw new IllegalArgumentException("Unknown filter type: " + filter.getClass());
+ }
+ }
+
+ private static final class ActionPage implements Page {
+ private final LogPage page;
+
+ private ActionPage(LogPage page) {
+ this.page = page;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Override
+ public @NonNull List entries() {
+ return (List) this.page.getContent();
+ }
+
+ @Override
+ public int overallSize() {
+ return this.page.getTotalEntries();
+ }
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateField.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateField.java
index eda70cb2a..03d674e03 100644
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateField.java
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateField.java
@@ -1,3 +1,28 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
package me.lucko.luckperms.common.bulkupdate;
import me.lucko.luckperms.common.filter.FilterField;
diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateSqlBuilder.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateSqlBuilder.java
index d1b5da243..63b25c200 100644
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateSqlBuilder.java
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateSqlBuilder.java
@@ -28,14 +28,10 @@ package me.lucko.luckperms.common.bulkupdate;
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.Filter;
import me.lucko.luckperms.common.filter.FilterField;
-import me.lucko.luckperms.common.filter.FilterList;
import me.lucko.luckperms.common.filter.sql.FilterSqlBuilder;
import net.luckperms.api.node.Node;
-import java.util.List;
-
public class BulkUpdateSqlBuilder extends FilterSqlBuilder {
public void visit(BulkUpdate update) {
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogGroupHistory.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogGroupHistory.java
index 334cf7816..9d8d56e14 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogGroupHistory.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogGroupHistory.java
@@ -59,13 +59,13 @@ public class LogGroupHistory extends ChildCommand {
return;
}
- PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, Integer.MIN_VALUE));
+ PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 1));
LogPage log = plugin.getStorage().getLogPage(ActionFilters.group(group), pageParams).join();
int page = pageParams.pageNumber();
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
- if (log.getContent().isEmpty()) {
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogRecent.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogRecent.java
index a06fd6f54..248c7acc1 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogRecent.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogRecent.java
@@ -74,7 +74,7 @@ public class LogRecent extends ChildCommand {
LogPage log = plugin.getStorage().getLogPage(uuid == null ? ActionFilters.all() : ActionFilters.source(uuid), pageParams).join();
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
- if (log.getContent().isEmpty()) {
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogSearch.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogSearch.java
index 3e5d89c1b..5af98e275 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogSearch.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogSearch.java
@@ -49,7 +49,7 @@ public class LogSearch extends ChildCommand {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
- int page = Integer.MIN_VALUE;
+ int page = 1;
if (args.size() > 1) {
try {
page = Integer.parseInt(args.get(args.size() - 1));
@@ -64,7 +64,7 @@ public class LogSearch extends ChildCommand {
LogPage log = plugin.getStorage().getLogPage(ActionFilters.search(query), pageParams).join();
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
- if (log.getContent().isEmpty()) {
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogTrackHistory.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogTrackHistory.java
index 2176fd45d..f88b2a94f 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogTrackHistory.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogTrackHistory.java
@@ -58,13 +58,13 @@ public class LogTrackHistory extends ChildCommand {
Message.TRACK_INVALID_ENTRY.send(sender, track);
return;
}
- PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, Integer.MIN_VALUE));
+ PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 1));
LogPage log = plugin.getStorage().getLogPage(ActionFilters.track(track), pageParams).join();
int page = pageParams.pageNumber();
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
- if (log.getContent().isEmpty()) {
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogUserHistory.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogUserHistory.java
index d8a0fca05..f12fbe560 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogUserHistory.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogUserHistory.java
@@ -55,13 +55,13 @@ public class LogUserHistory extends ChildCommand {
return;
}
- PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, Integer.MIN_VALUE));
+ PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 1));
LogPage log = plugin.getStorage().getLogPage(ActionFilters.user(uuid), pageParams).join();
int page = pageParams.pageNumber();
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
- if (log.getContent().isEmpty()) {
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java
index 120d9fd2a..495f3296f 100644
--- a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java
+++ b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java
@@ -443,6 +443,11 @@ public final class ConfigKeys {
.collect(ImmutableCollectors.toList());
});
+ /**
+ * If log should be posted synchronously to storage/messaging in commands
+ */
+ public static final ConfigKey LOG_SYNCHRONOUSLY_IN_COMMANDS = booleanKey("log-synchronously-in-commands", false);
+
/**
* If LuckPerms should automatically install translation bundles and periodically update them.
*/
diff --git a/common/src/main/java/me/lucko/luckperms/common/filter/ConstraintFactory.java b/common/src/main/java/me/lucko/luckperms/common/filter/ConstraintFactory.java
index a3b763cfb..a7897384a 100644
--- a/common/src/main/java/me/lucko/luckperms/common/filter/ConstraintFactory.java
+++ b/common/src/main/java/me/lucko/luckperms/common/filter/ConstraintFactory.java
@@ -1,3 +1,28 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
package me.lucko.luckperms.common.filter;
import java.util.UUID;
diff --git a/common/src/main/java/me/lucko/luckperms/common/filter/FilterList.java b/common/src/main/java/me/lucko/luckperms/common/filter/FilterList.java
index eca53064d..c70d4d32c 100644
--- a/common/src/main/java/me/lucko/luckperms/common/filter/FilterList.java
+++ b/common/src/main/java/me/lucko/luckperms/common/filter/FilterList.java
@@ -1,3 +1,28 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
package me.lucko.luckperms.common.filter;
import com.google.common.collect.ForwardingList;
diff --git a/common/src/main/java/me/lucko/luckperms/common/filter/sql/ConstraintSqlBuilder.java b/common/src/main/java/me/lucko/luckperms/common/filter/sql/ConstraintSqlBuilder.java
index c5f776aaa..04e5d7fc5 100644
--- a/common/src/main/java/me/lucko/luckperms/common/filter/sql/ConstraintSqlBuilder.java
+++ b/common/src/main/java/me/lucko/luckperms/common/filter/sql/ConstraintSqlBuilder.java
@@ -1,3 +1,28 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
package me.lucko.luckperms.common.filter.sql;
import me.lucko.luckperms.common.filter.Comparison;
diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java
index 26b26ec62..a54a2cc14 100644
--- a/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java
+++ b/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java
@@ -31,6 +31,8 @@ import net.luckperms.api.actionlog.Action;
import net.luckperms.api.messenger.Messenger;
import net.luckperms.api.messenger.MessengerProvider;
+import java.util.concurrent.CompletableFuture;
+
public interface InternalMessagingService {
/**
@@ -60,21 +62,21 @@ public interface InternalMessagingService {
* Uses the messaging service to inform other servers about a general
* change.
*/
- void pushUpdate();
+ CompletableFuture pushUpdate();
/**
* Pushes an update for a specific user.
*
* @param user the user
*/
- void pushUserUpdate(User user);
+ CompletableFuture pushUserUpdate(User user);
/**
* Pushes a log entry to connected servers.
*
* @param logEntry the log entry
*/
- void pushLog(Action logEntry);
+ CompletableFuture pushLog(Action logEntry);
/**
* Pushes a custom payload to connected servers.
@@ -82,6 +84,6 @@ public interface InternalMessagingService {
* @param channelId the channel id
* @param payload the payload
*/
- void pushCustomPayload(String channelId, String payload);
+ CompletableFuture pushCustomPayload(String channelId, String payload);
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java
index e828d032b..508fb8906 100644
--- a/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java
+++ b/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java
@@ -36,6 +36,7 @@ import me.lucko.luckperms.common.messaging.message.UpdateMessageImpl;
import me.lucko.luckperms.common.messaging.message.UserUpdateMessageImpl;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
+import me.lucko.luckperms.common.util.AsyncInterface;
import me.lucko.luckperms.common.util.ExpiringSet;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.util.gson.JObject;
@@ -54,9 +55,10 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Objects;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
-public class LuckPermsMessagingService implements InternalMessagingService, IncomingMessageConsumer {
+public class LuckPermsMessagingService extends AsyncInterface implements InternalMessagingService, IncomingMessageConsumer {
private final LuckPermsPlugin plugin;
private final ExpiringSet receivedMessages;
private final PushUpdateBuffer updateBuffer;
@@ -65,6 +67,7 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
private final Messenger messenger;
public LuckPermsMessagingService(LuckPermsPlugin plugin, MessengerProvider messengerProvider) {
+ super(plugin);
this.plugin = plugin;
this.messengerProvider = messengerProvider;
@@ -107,8 +110,8 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
}
@Override
- public void pushUpdate() {
- this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
+ public CompletableFuture pushUpdate() {
+ return future(() -> {
UUID requestId = generatePingId();
this.plugin.getLogger().info("[Messaging] Sending ping with id: " + requestId);
this.messenger.sendOutgoingMessage(new UpdateMessageImpl(requestId));
@@ -116,8 +119,8 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
}
@Override
- public void pushUserUpdate(User user) {
- this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
+ public CompletableFuture pushUserUpdate(User user) {
+ return future(() -> {
UUID requestId = generatePingId();
this.plugin.getLogger().info("[Messaging] Sending user ping for '" + user.getPlainDisplayName() + "' with id: " + requestId);
this.messenger.sendOutgoingMessage(new UserUpdateMessageImpl(requestId, user.getUniqueId()));
@@ -125,8 +128,8 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
}
@Override
- public void pushLog(Action logEntry) {
- this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
+ public CompletableFuture pushLog(Action logEntry) {
+ return future(() -> {
UUID requestId = generatePingId();
if (this.plugin.getEventDispatcher().dispatchLogNetworkPublish(!this.plugin.getConfiguration().get(ConfigKeys.PUSH_LOG_ENTRIES), requestId, logEntry)) {
@@ -139,8 +142,8 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
}
@Override
- public void pushCustomPayload(String channelId, String payload) {
- this.plugin.getBootstrap().getScheduler().executeAsync(() -> {
+ public CompletableFuture pushCustomPayload(String channelId, String payload) {
+ return future(() -> {
UUID requestId = generatePingId();
this.messenger.sendOutgoingMessage(new CustomMessageImpl(requestId, channelId, payload));
});
@@ -283,7 +286,7 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco
ActionLogMessage msg = (ActionLogMessage) message;
this.plugin.getEventDispatcher().dispatchLogReceive(msg.getId(), msg.getAction());
- this.plugin.getLogDispatcher().dispatchFromRemote((LoggedAction) msg.getAction());
+ this.plugin.getLogDispatcher().broadcastFromRemote((LoggedAction) msg.getAction());
} else if (message instanceof CustomMessage) {
CustomMessage msg = (CustomMessage) message;
diff --git a/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java b/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java
index 9d12ca53d..97b072493 100644
--- a/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java
+++ b/common/src/main/java/me/lucko/luckperms/common/sender/AbstractSender.java
@@ -78,7 +78,7 @@ public final class AbstractSender implements Sender {
@Override
public void sendMessage(Component message) {
- if (isConsole()) {
+ if (this.factory.shouldSplitNewlines(this.sender)) {
for (Component line : splitNewlines(message)) {
this.factory.sendMessage(this.sender, line);
}
@@ -89,12 +89,12 @@ public final class AbstractSender implements Sender {
@Override
public Tristate getPermissionValue(String permission) {
- return (isConsole() && this.factory.consoleHasAllPermissions()) ? Tristate.TRUE : this.factory.getPermissionValue(this.sender, permission);
+ return isConsole() ? Tristate.TRUE : this.factory.getPermissionValue(this.sender, permission);
}
@Override
public boolean hasPermission(String permission) {
- return (isConsole() && this.factory.consoleHasAllPermissions()) || this.factory.hasPermission(this.sender, permission);
+ return isConsole() || this.factory.hasPermission(this.sender, permission);
}
@Override
diff --git a/common/src/main/java/me/lucko/luckperms/common/sender/SenderFactory.java b/common/src/main/java/me/lucko/luckperms/common/sender/SenderFactory.java
index 0ec94ac84..5c020afdd 100644
--- a/common/src/main/java/me/lucko/luckperms/common/sender/SenderFactory.java
+++ b/common/src/main/java/me/lucko/luckperms/common/sender/SenderFactory.java
@@ -63,8 +63,8 @@ public abstract class SenderFactory implements Aut
protected abstract boolean isConsole(T sender);
- protected boolean consoleHasAllPermissions() {
- return true;
+ protected boolean shouldSplitNewlines(T sender) {
+ return isConsole(sender);
}
public final Sender wrap(T sender) {
diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java
index 6adb20531..0f89eecb7 100644
--- a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java
+++ b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java
@@ -38,7 +38,7 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.implementation.StorageImplementation;
import me.lucko.luckperms.common.storage.implementation.split.SplitStorage;
import me.lucko.luckperms.common.storage.misc.NodeEntry;
-import me.lucko.luckperms.common.util.Throwing;
+import me.lucko.luckperms.common.util.AsyncInterface;
import net.luckperms.api.actionlog.Action;
import net.luckperms.api.event.cause.CreationCause;
import net.luckperms.api.event.cause.DeletionCause;
@@ -54,18 +54,17 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
-import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
/**
* Provides a {@link CompletableFuture} based API for interacting with a {@link StorageImplementation}.
*/
-public class Storage {
+public class Storage extends AsyncInterface {
private final LuckPermsPlugin plugin;
private final StorageImplementation implementation;
public Storage(LuckPermsPlugin plugin, StorageImplementation implementation) {
+ super(plugin);
this.plugin = plugin;
this.implementation = implementation;
}
@@ -82,32 +81,6 @@ public class Storage {
}
}
- private CompletableFuture future(Callable supplier) {
- return CompletableFuture.supplyAsync(() -> {
- try {
- return supplier.call();
- } catch (Exception e) {
- if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- }
- throw new CompletionException(e);
- }
- }, this.plugin.getBootstrap().getScheduler().async());
- }
-
- private CompletableFuture future(Throwing.Runnable runnable) {
- return CompletableFuture.runAsync(() -> {
- try {
- runnable.run();
- } catch (Exception e) {
- if (e instanceof RuntimeException) {
- throw (RuntimeException) e;
- }
- throw new CompletionException(e);
- }
- }, this.plugin.getBootstrap().getScheduler().async());
- }
-
public String getName() {
return this.implementation.getImplementationName();
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/FileActionLogger.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/FileActionLogger.java
index 1b9105c91..e657e7bbc 100644
--- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/FileActionLogger.java
+++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/file/FileActionLogger.java
@@ -137,7 +137,7 @@ public class FileActionLogger {
}
}
- private Stream getRawLog() throws IOException {
+ private Stream loadLog(FilterList filters) throws IOException {
// if there is log content waiting to be written, flush immediately before trying to read
if (this.saveBuffer.isEnqueued()) {
this.saveBuffer.requestDirectly();
@@ -153,7 +153,10 @@ public class FileActionLogger {
while ((line = reader.readLine()) != null) {
try {
JsonElement parsed = GsonProvider.parser().parse(line);
- builder.add(ActionJsonSerializer.deserialize(parsed));
+ LoggedAction action = ActionJsonSerializer.deserialize(parsed);
+ if (filters.evaluate(action)) {
+ builder.add(action);
+ }
} catch (Exception e) {
e.printStackTrace();
}
@@ -163,10 +166,10 @@ public class FileActionLogger {
}
public LogPage getLogPage(FilterList filters, @Nullable PageParameters page) throws IOException {
- List filtered = getRawLog()
- .filter(filters::evaluate)
- .sorted(Comparator.reverseOrder())
- .collect(Collectors.toList());
+ List filtered = loadLog(filters)
+ .sorted(Comparator.comparing(LoggedAction::getTimestamp))
+ .collect(Collectors.toList())
+ .reversed();
int size = filtered.size();
List paginated = page != null ? page.paginate(filtered) : filtered;
diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/mongodb/MongoStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/mongodb/MongoStorage.java
index 68cf79165..922e096bb 100644
--- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/mongodb/MongoStorage.java
+++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/mongodb/MongoStorage.java
@@ -186,7 +186,7 @@ public class MongoStorage implements StorageImplementation {
long count = c.countDocuments(filter);
List content = new ArrayList<>();
- try (MongoCursor cursor = ConstraintMongoBuilder.page(page, c.find(filter).sort(Sorts.descending("timestamp"))).iterator()) {
+ try (MongoCursor cursor = ConstraintMongoBuilder.page(page, c.find(filter).sort(Sorts.descending("timestamp", "_id"))).iterator()) {
while (cursor.hasNext()) {
content.add(actionFromDoc(cursor.next()));
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/SqlStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/SqlStorage.java
index 8924fb327..321b814ea 100644
--- a/common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/SqlStorage.java
+++ b/common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/SqlStorage.java
@@ -268,7 +268,7 @@ public class SqlStorage implements StorageImplementation {
ActionFilterSqlBuilder sqlBuilder = new ActionFilterSqlBuilder();
sqlBuilder.builder().append(ACTION_SELECT_ALL);
sqlBuilder.visit(filter);
- sqlBuilder.builder().append(" ORDER BY time DESC");
+ sqlBuilder.builder().append(" ORDER BY time DESC, id DESC");
sqlBuilder.visit(page);
try (PreparedStatement ps = sqlBuilder.builder().build(c, this.statementProcessor)) {
diff --git a/common/src/main/java/me/lucko/luckperms/common/util/AsyncInterface.java b/common/src/main/java/me/lucko/luckperms/common/util/AsyncInterface.java
new file mode 100644
index 000000000..d1996226e
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/util/AsyncInterface.java
@@ -0,0 +1,71 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.lucko.luckperms.common.util;
+
+import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+
+/**
+ * Base class for an interface which can perform operations asynchronously and return {@link CompletableFuture}s
+ */
+public abstract class AsyncInterface {
+
+ private final LuckPermsPlugin plugin;
+
+ protected AsyncInterface(LuckPermsPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ protected CompletableFuture future(Callable supplier) {
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ return supplier.call();
+ } catch (Exception e) {
+ if (e instanceof RuntimeException) {
+ throw (RuntimeException) e;
+ }
+ throw new CompletionException(e);
+ }
+ }, this.plugin.getBootstrap().getScheduler().async());
+ }
+
+ protected CompletableFuture future(Throwing.Runnable runnable) {
+ return CompletableFuture.runAsync(() -> {
+ try {
+ runnable.run();
+ } catch (Exception e) {
+ if (e instanceof RuntimeException) {
+ throw (RuntimeException) e;
+ }
+ throw new CompletionException(e);
+ }
+ }, this.plugin.getBootstrap().getScheduler().async());
+ }
+
+}
diff --git a/common/src/test/java/me/lucko/luckperms/common/actionlog/ActionFilterMongoTest.java b/common/src/test/java/me/lucko/luckperms/common/actionlog/ActionFilterMongoTest.java
index 24f3d3fa4..f3920b67d 100644
--- a/common/src/test/java/me/lucko/luckperms/common/actionlog/ActionFilterMongoTest.java
+++ b/common/src/test/java/me/lucko/luckperms/common/actionlog/ActionFilterMongoTest.java
@@ -54,18 +54,18 @@ public class ActionFilterMongoTest {
),
Arguments.of(
ActionFilters.user(UUID.fromString("725d585e-4ff1-4f18-acca-6ac538364080")),
- // {"$and": [{"target.type": "U"}, {"target.uniqueId": {"$binary": {"base64": "cl1YXk/xTxisymrFODZAgA==", "subType": "04"}}}]}
- "{\"$and\": [{\"target.type\": \"U\"}, {\"target.uniqueId\": {\"$binary\": {\"base64\": \"cl1YXk/xTxisymrFODZAgA==\", \"subType\": \"04\"}}}]}"
+ // {"$and": [{"target.type": "USER"}, {"target.uniqueId": {"$binary": {"base64": "cl1YXk/xTxisymrFODZAgA==", "subType": "04"}}}]}
+ "{\"$and\": [{\"target.type\": \"USER\"}, {\"target.uniqueId\": {\"$binary\": {\"base64\": \"cl1YXk/xTxisymrFODZAgA==\", \"subType\": \"04\"}}}]}"
),
Arguments.of(
ActionFilters.group("test"),
- // {"$and": [{"target.type": "G"}, {"target.name": "test"}]}
- "{\"$and\": [{\"target.type\": \"G\"}, {\"target.name\": \"test\"}]}"
+ // {"$and": [{"target.type": "GROUP"}, {"target.name": "test"}]}
+ "{\"$and\": [{\"target.type\": \"GROUP\"}, {\"target.name\": \"test\"}]}"
),
Arguments.of(
ActionFilters.track("test"),
- // {"$and": [{"target.type": "T"}, {"target.name": "test"}]}
- "{\"$and\": [{\"target.type\": \"T\"}, {\"target.name\": \"test\"}]}"
+ // {"$and": [{"target.type": "TRACK"}, {"target.name": "test"}]}
+ "{\"$and\": [{\"target.type\": \"TRACK\"}, {\"target.name\": \"test\"}]}"
),
Arguments.of(
ActionFilters.search("test"),
diff --git a/common/src/test/java/me/lucko/luckperms/common/storage/AbstractStorageTest.java b/common/src/test/java/me/lucko/luckperms/common/storage/AbstractStorageTest.java
index b20e5f255..cf5025a6d 100644
--- a/common/src/test/java/me/lucko/luckperms/common/storage/AbstractStorageTest.java
+++ b/common/src/test/java/me/lucko/luckperms/common/storage/AbstractStorageTest.java
@@ -152,6 +152,7 @@ public abstract class AbstractStorageTest {
.targetType(Action.Target.Type.GROUP)
.targetName(i % 2 == 0 ? "test_group" : "dummy")
.description("group test " + i)
+ .timestamp(baseTime)
.build());
}
@@ -162,6 +163,7 @@ public abstract class AbstractStorageTest {
.targetType(Action.Target.Type.TRACK)
.targetName(i % 2 == 0 ? "test_track" : "dummy")
.description("track test " + i)
+ .timestamp(baseTime)
.build());
}
@@ -210,9 +212,17 @@ public abstract class AbstractStorageTest {
page = this.storage.getLogPage(ActionFilters.group("test_group"), new PageParameters(10, 1));
assertEquals(5, page.getContent().size());
+ assertEquals(
+ ImmutableList.of("group test 8", "group test 6", "group test 4", "group test 2", "group test 0"),
+ page.getContent().stream().map(LoggedAction::getDescription).collect(Collectors.toList())
+ );
page = this.storage.getLogPage(ActionFilters.track("test_track"), new PageParameters(10, 1));
assertEquals(5, page.getContent().size());
+ assertEquals(
+ ImmutableList.of("track test 8", "track test 6", "track test 4", "track test 2", "track test 0"),
+ page.getContent().stream().map(LoggedAction::getDescription).collect(Collectors.toList())
+ );
page = this.storage.getLogPage(ActionFilters.search("hello"), new PageParameters(500, 1));
assertEquals(300, page.getContent().size());
diff --git a/common/src/test/java/me/lucko/luckperms/common/storage/ConfigurateStorageTest.java b/common/src/test/java/me/lucko/luckperms/common/storage/ConfigurateStorageTest.java
index 45038a4ba..22d1db444 100644
--- a/common/src/test/java/me/lucko/luckperms/common/storage/ConfigurateStorageTest.java
+++ b/common/src/test/java/me/lucko/luckperms/common/storage/ConfigurateStorageTest.java
@@ -1,3 +1,28 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
package me.lucko.luckperms.common.storage;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
diff --git a/common/src/test/java/me/lucko/luckperms/common/storage/MongoStorageTest.java b/common/src/test/java/me/lucko/luckperms/common/storage/MongoStorageTest.java
index 668632884..cc28698da 100644
--- a/common/src/test/java/me/lucko/luckperms/common/storage/MongoStorageTest.java
+++ b/common/src/test/java/me/lucko/luckperms/common/storage/MongoStorageTest.java
@@ -1,3 +1,28 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
package me.lucko.luckperms.common.storage;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
diff --git a/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/CommandExecutor.java b/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/CommandExecutor.java
index 8cdec14c9..c5d92a1e5 100644
--- a/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/CommandExecutor.java
+++ b/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/CommandExecutor.java
@@ -33,8 +33,16 @@ import java.util.concurrent.CompletableFuture;
*/
public interface CommandExecutor {
- CompletableFuture execute(String command);
+ CompletableFuture execute(StandaloneSender player, String command);
- List tabComplete(String command);
+ List tabComplete(StandaloneSender player, String command);
+
+ default CompletableFuture execute(String command) {
+ return execute(StandaloneUser.INSTANCE, command);
+ }
+
+ default List tabComplete(String command) {
+ return tabComplete(StandaloneUser.INSTANCE, command);
+ }
}
diff --git a/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/StandaloneSender.java b/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/StandaloneSender.java
new file mode 100644
index 000000000..eea1ad817
--- /dev/null
+++ b/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/StandaloneSender.java
@@ -0,0 +1,48 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.lucko.luckperms.standalone.app.integration;
+
+import net.kyori.adventure.text.Component;
+import net.luckperms.api.util.Tristate;
+
+import java.util.Locale;
+import java.util.UUID;
+
+public interface StandaloneSender {
+ String getName();
+
+ UUID getUniqueId();
+
+ void sendMessage(Component component);
+
+ Tristate getPermissionValue(String permission);
+
+ boolean hasPermission(String permission);
+
+ boolean isConsole();
+
+ Locale getLocale();
+}
diff --git a/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/SingletonPlayer.java b/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/StandaloneUser.java
similarity index 57%
rename from standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/SingletonPlayer.java
rename to standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/StandaloneUser.java
index 4a750d098..4d98b009f 100644
--- a/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/SingletonPlayer.java
+++ b/standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/StandaloneUser.java
@@ -28,57 +28,57 @@ 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.luckperms.api.util.Tristate;
-import java.util.Set;
+import java.util.Locale;
import java.util.UUID;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.function.Consumer;
/**
- * Dummy/singleton player class used by the standalone plugin.
- *
- * In various places (ContextManager, SenderFactory, ..) the platform "player" type is used
- * as a generic parameter. This class acts as this type for the standalone plugin.
+ * The sender instance used for the console / users executing commands
+ * on a standalone instance of LuckPerms
*/
-public class SingletonPlayer {
+public class StandaloneUser implements StandaloneSender {
- /** Empty UUID used by the singleton player. */
private static final UUID UUID = new UUID(0, 0);
- /** A message sink that prints the component to stdout */
- private static final Consumer PRINT_TO_STDOUT = component -> LuckPermsApplication.LOGGER.info(ANSIComponentSerializer.ansi().serialize(component));
+ public static final StandaloneUser INSTANCE = new StandaloneUser();
- /** Singleton instance */
- public static final SingletonPlayer INSTANCE = new SingletonPlayer();
-
- /** A set of message sinks that messages are delivered to */
- private final Set> messageSinks;
-
- private SingletonPlayer() {
- this.messageSinks = new CopyOnWriteArraySet<>();
- this.messageSinks.add(PRINT_TO_STDOUT);
+ private StandaloneUser() {
}
+ @Override
public String getName() {
return "StandaloneUser";
}
+ @Override
public UUID getUniqueId() {
return UUID;
}
+ @Override
public void sendMessage(Component component) {
- for (Consumer sink : this.messageSinks) {
- sink.accept(component);
- }
+ LuckPermsApplication.LOGGER.info(ANSIComponentSerializer.ansi().serialize(component));
}
- public void addMessageSink(Consumer sink) {
- this.messageSinks.add(sink);
+ @Override
+ public Tristate getPermissionValue(String permission) {
+ return Tristate.TRUE;
}
- public void removeMessageSink(Consumer sink) {
- this.messageSinks.remove(sink);
+ @Override
+ public boolean hasPermission(String permission) {
+ return true;
+ }
+
+ @Override
+ public boolean isConsole() {
+ return true;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return Locale.getDefault();
}
}
diff --git a/standalone/src/main/java/me/lucko/luckperms/standalone/LPStandalonePlugin.java b/standalone/src/main/java/me/lucko/luckperms/standalone/LPStandalonePlugin.java
index 609b785e3..3970faa0b 100644
--- a/standalone/src/main/java/me/lucko/luckperms/standalone/LPStandalonePlugin.java
+++ b/standalone/src/main/java/me/lucko/luckperms/standalone/LPStandalonePlugin.java
@@ -39,7 +39,7 @@ import me.lucko.luckperms.common.plugin.AbstractLuckPermsPlugin;
import me.lucko.luckperms.common.plugin.util.AbstractConnectionListener;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.standalone.app.LuckPermsApplication;
-import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
+import me.lucko.luckperms.standalone.app.integration.StandaloneUser;
import me.lucko.luckperms.standalone.stub.StandaloneContextManager;
import me.lucko.luckperms.standalone.stub.StandaloneDummyConnectionListener;
import me.lucko.luckperms.standalone.stub.StandaloneEventBus;
@@ -162,7 +162,7 @@ public class LPStandalonePlugin extends AbstractLuckPermsPlugin {
@Override
public Sender getConsoleSender() {
- return getSenderFactory().wrap(SingletonPlayer.INSTANCE);
+ return getSenderFactory().wrap(StandaloneUser.INSTANCE);
}
public StandaloneSenderFactory getSenderFactory() {
diff --git a/standalone/src/main/java/me/lucko/luckperms/standalone/StandaloneCommandManager.java b/standalone/src/main/java/me/lucko/luckperms/standalone/StandaloneCommandManager.java
index 4e2c2d0a5..e1b67bce1 100644
--- a/standalone/src/main/java/me/lucko/luckperms/standalone/StandaloneCommandManager.java
+++ b/standalone/src/main/java/me/lucko/luckperms/standalone/StandaloneCommandManager.java
@@ -29,7 +29,7 @@ import me.lucko.luckperms.common.command.CommandManager;
import me.lucko.luckperms.common.command.utils.ArgumentTokenizer;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.standalone.app.integration.CommandExecutor;
-import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
+import me.lucko.luckperms.standalone.app.integration.StandaloneSender;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -43,15 +43,15 @@ public class StandaloneCommandManager extends CommandManager implements CommandE
}
@Override
- public CompletableFuture execute(String command) {
- Sender wrapped = this.plugin.getSenderFactory().wrap(SingletonPlayer.INSTANCE);
+ public CompletableFuture execute(StandaloneSender player, String command) {
+ Sender wrapped = this.plugin.getSenderFactory().wrap(player);
List arguments = ArgumentTokenizer.EXECUTE.tokenizeInput(command);
return executeCommand(wrapped, "lp", arguments);
}
@Override
- public List tabComplete(String command) {
- Sender wrapped = this.plugin.getSenderFactory().wrap(SingletonPlayer.INSTANCE);
+ public List tabComplete(StandaloneSender player, String command) {
+ Sender wrapped = this.plugin.getSenderFactory().wrap(player);
List arguments = ArgumentTokenizer.TAB_COMPLETE.tokenizeInput(command);
return tabCompleteCommand(wrapped, arguments);
}
diff --git a/standalone/src/main/java/me/lucko/luckperms/standalone/StandaloneSenderFactory.java b/standalone/src/main/java/me/lucko/luckperms/standalone/StandaloneSenderFactory.java
index ca21170a1..eec85c5b5 100644
--- a/standalone/src/main/java/me/lucko/luckperms/standalone/StandaloneSenderFactory.java
+++ b/standalone/src/main/java/me/lucko/luckperms/standalone/StandaloneSenderFactory.java
@@ -27,53 +27,56 @@ package me.lucko.luckperms.standalone;
import me.lucko.luckperms.common.locale.TranslationManager;
import me.lucko.luckperms.common.sender.SenderFactory;
-import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
+import me.lucko.luckperms.standalone.app.integration.StandaloneSender;
import net.kyori.adventure.text.Component;
import net.luckperms.api.util.Tristate;
-import java.util.Locale;
import java.util.UUID;
-public class StandaloneSenderFactory extends SenderFactory {
+public class StandaloneSenderFactory extends SenderFactory {
public StandaloneSenderFactory(LPStandalonePlugin plugin) {
super(plugin);
}
@Override
- protected String getName(SingletonPlayer sender) {
+ protected String getName(StandaloneSender sender) {
return sender.getName();
}
@Override
- protected UUID getUniqueId(SingletonPlayer sender) {
+ protected UUID getUniqueId(StandaloneSender sender) {
return sender.getUniqueId();
}
@Override
- protected void sendMessage(SingletonPlayer sender, Component message) {
- Component rendered = TranslationManager.render(message, Locale.getDefault());
+ protected void sendMessage(StandaloneSender sender, Component message) {
+ Component rendered = TranslationManager.render(message, sender.getLocale());
sender.sendMessage(rendered);
}
@Override
- protected Tristate getPermissionValue(SingletonPlayer sender, String node) {
- return Tristate.TRUE;
+ protected Tristate getPermissionValue(StandaloneSender sender, String node) {
+ return sender.getPermissionValue(node);
}
@Override
- protected boolean hasPermission(SingletonPlayer sender, String node) {
+ protected boolean hasPermission(StandaloneSender sender, String node) {
+ return sender.hasPermission(node);
+ }
+
+ @Override
+ protected void performCommand(StandaloneSender sender, String command) {
+
+ }
+
+ @Override
+ protected boolean isConsole(StandaloneSender sender) {
+ return sender.isConsole();
+ }
+
+ @Override
+ protected boolean shouldSplitNewlines(StandaloneSender sender) {
return true;
}
-
- @Override
- protected void performCommand(SingletonPlayer sender, String command) {
-
- }
-
- @Override
- protected boolean isConsole(SingletonPlayer sender) {
- return true;
- }
-
}
diff --git a/standalone/src/main/java/me/lucko/luckperms/standalone/stub/StandaloneContextManager.java b/standalone/src/main/java/me/lucko/luckperms/standalone/stub/StandaloneContextManager.java
index 43cfde390..35d48d7bd 100644
--- a/standalone/src/main/java/me/lucko/luckperms/standalone/stub/StandaloneContextManager.java
+++ b/standalone/src/main/java/me/lucko/luckperms/standalone/stub/StandaloneContextManager.java
@@ -29,39 +29,45 @@ import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.context.manager.ContextManager;
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
import me.lucko.luckperms.standalone.LPStandalonePlugin;
-import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
+import me.lucko.luckperms.standalone.app.integration.StandaloneSender;
+import me.lucko.luckperms.standalone.app.integration.StandaloneUser;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.query.QueryOptions;
import java.util.UUID;
-public class StandaloneContextManager extends ContextManager {
- private final QueryOptionsCache singletonCache = new QueryOptionsCache<>(SingletonPlayer.INSTANCE, this);
+public class StandaloneContextManager extends ContextManager {
+ private final QueryOptionsCache singletonCache = new QueryOptionsCache<>(StandaloneUser.INSTANCE, this);
public StandaloneContextManager(LPStandalonePlugin plugin) {
- super(plugin, SingletonPlayer.class, SingletonPlayer.class);
+ super(plugin, StandaloneSender.class, StandaloneSender.class);
}
@Override
- public UUID getUniqueId(SingletonPlayer player) {
+ public UUID getUniqueId(StandaloneSender player) {
return player.getUniqueId();
}
@Override
- public QueryOptionsCache getCacheFor(SingletonPlayer subject) {
+ public QueryOptionsCache getCacheFor(StandaloneSender subject) {
if (subject == null) {
throw new NullPointerException("subject");
}
- return this.singletonCache;
+ if (subject == StandaloneUser.INSTANCE) {
+ return this.singletonCache;
+ }
+
+ // just return a new one every time - not optimal but this case should only be hit using unit tests anyway
+ return new QueryOptionsCache<>(subject, this);
}
@Override
- protected void invalidateCache(SingletonPlayer subject) {
+ protected void invalidateCache(StandaloneSender subject) {
this.singletonCache.invalidate();
}
@Override
- public QueryOptions formQueryOptions(SingletonPlayer subject, ImmutableContextSet contextSet) {
+ public QueryOptions formQueryOptions(StandaloneSender subject, ImmutableContextSet contextSet) {
QueryOptions.Builder queryOptions = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder();
return queryOptions.context(contextSet).build();
}
diff --git a/standalone/src/test/java/me/lucko/luckperms/standalone/CommandsIntegrationTest.java b/standalone/src/test/java/me/lucko/luckperms/standalone/CommandsIntegrationTest.java
index 485a3ccbe..362825e84 100644
--- a/standalone/src/test/java/me/lucko/luckperms/standalone/CommandsIntegrationTest.java
+++ b/standalone/src/test/java/me/lucko/luckperms/standalone/CommandsIntegrationTest.java
@@ -29,9 +29,9 @@ import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.types.Inheritance;
import me.lucko.luckperms.standalone.app.integration.CommandExecutor;
-import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
import me.lucko.luckperms.standalone.utils.CommandTester;
import me.lucko.luckperms.standalone.utils.TestPluginProvider;
+import me.lucko.luckperms.standalone.utils.TestSender;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.luckperms.api.event.log.LogNotifyEvent;
import org.junit.jupiter.api.Test;
@@ -54,6 +54,7 @@ public class CommandsIntegrationTest {
private static final Map CONFIG = ImmutableMap.builder()
.put("log-notify", "false")
+ .put("commands-rate-limit", "false")
.build();
@Test
@@ -61,7 +62,7 @@ public class CommandsIntegrationTest {
TestPluginProvider.use(tempDir, CONFIG, (app, bootstrap, plugin) -> {
CommandExecutor executor = app.getCommandExecutor();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.givenHasPermissions("luckperms.creategroup")
.whenRunCommand("creategroup test")
.thenExpect("[LP] test was successfully created.")
@@ -97,9 +98,9 @@ public class CommandsIntegrationTest {
"""
)
- .givenHasAllPermissions()
+ .givenHasPermissions("luckperms.group.meta.set")
.whenRunCommand("group test meta set hello world")
- .clearMessageBuffer()
+ .thenExpect("[LP] Set meta key 'hello' to 'world' for test in context global.")
.givenHasPermissions("luckperms.group.setweight")
.whenRunCommand("group test setweight 10")
@@ -182,7 +183,7 @@ public class CommandsIntegrationTest {
TestPluginProvider.use(tempDir, CONFIG, (app, bootstrap, plugin) -> {
CommandExecutor executor = app.getCommandExecutor();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.whenRunCommand("creategroup test")
.clearMessageBuffer()
@@ -262,7 +263,7 @@ public class CommandsIntegrationTest {
TestPluginProvider.use(tempDir, CONFIG, (app, bootstrap, plugin) -> {
CommandExecutor executor = app.getCommandExecutor();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.whenRunCommand("creategroup test")
.whenRunCommand("creategroup test2")
.whenRunCommand("creategroup test3")
@@ -321,7 +322,7 @@ public class CommandsIntegrationTest {
TestPluginProvider.use(tempDir, CONFIG, (app, bootstrap, plugin) -> {
CommandExecutor executor = app.getCommandExecutor();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.whenRunCommand("creategroup test")
.clearMessageBuffer()
@@ -445,7 +446,7 @@ public class CommandsIntegrationTest {
plugin.getStorage().savePlayerData(UUID.fromString("c1d60c50-70b5-4722-8057-87767557e50d"), "Luck").join();
plugin.getStorage().savePlayerData(UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5"), "Notch").join();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.givenHasPermissions("luckperms.user.info")
.whenRunCommand("user Luck info")
.thenExpect("""
@@ -508,7 +509,7 @@ public class CommandsIntegrationTest {
plugin.getStorage().savePlayerData(UUID.fromString("c1d60c50-70b5-4722-8057-87767557e50d"), "Luck").join();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.givenHasPermissions("luckperms.user.permission.set")
.whenRunCommand("user Luck permission set test.node true")
.thenExpect("[LP] Set test.node to true for luck in context global.")
@@ -587,7 +588,7 @@ public class CommandsIntegrationTest {
plugin.getStorage().savePlayerData(UUID.fromString("c1d60c50-70b5-4722-8057-87767557e50d"), "Luck").join();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.whenRunCommand("creategroup test2")
.whenRunCommand("creategroup test3")
.clearMessageBuffer()
@@ -651,7 +652,7 @@ public class CommandsIntegrationTest {
plugin.getStorage().savePlayerData(UUID.fromString("c1d60c50-70b5-4722-8057-87767557e50d"), "Luck").join();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.givenHasPermissions("luckperms.user.meta.info")
.whenRunCommand("user Luck meta info")
.thenExpect("""
@@ -773,7 +774,7 @@ public class CommandsIntegrationTest {
TestPluginProvider.use(tempDir, CONFIG, (app, bootstrap, plugin) -> {
CommandExecutor executor = app.getCommandExecutor();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.givenHasPermissions("luckperms.createtrack")
.whenRunCommand("createtrack test1")
.thenExpect("[LP] test1 was successfully created.")
@@ -884,7 +885,7 @@ public class CommandsIntegrationTest {
plugin.getStorage().savePlayerData(UUID.fromString("c1d60c50-70b5-4722-8057-87767557e50d"), "Luck").join();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.whenRunCommand("createtrack staff")
.whenRunCommand("createtrack premium")
@@ -1023,7 +1024,7 @@ public class CommandsIntegrationTest {
plugin.getStorage().savePlayerData(UUID.fromString("c1d60c50-70b5-4722-8057-87767557e50d"), "Luck").join();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.whenRunCommand("creategroup test")
.whenRunCommand("user Luck permission set hello.world true server=survival")
.whenRunCommand("group test permission set hello.world true world=nether")
@@ -1045,12 +1046,12 @@ public class CommandsIntegrationTest {
.givenHasPermissions("luckperms.search")
.whenRunCommand("search ~~ group.%")
.thenExpect("""
- [LP] Searching for users and groups with permissions ~~ group.%...
- [LP] Found 2 entries from 2 users and 0 groups.
- [LP] Showing user entries: (page 1 of 1 - 2 entries)
- > luck - (group.test) - true
- > luck - (group.default) - true
- """
+ [LP] Searching for users and groups with permissions ~~ group.%...
+ [LP] Found 2 entries from 2 users and 0 groups.
+ [LP] Showing user entries: (page 1 of 1 - 2 entries)
+ > luck - (group.test) - true
+ > luck - (group.default) - true
+ """
);
});
}
@@ -1068,14 +1069,16 @@ public class CommandsIntegrationTest {
CountDownLatch completed = new CountDownLatch(1);
- SingletonPlayer.INSTANCE.addMessageSink(component -> {
+ TestSender console = new TestSender();
+ console.setConsole(true);
+ console.addMessageSink(component -> {
String plain = PlainTextComponentSerializer.plainText().serialize(component);
if (plain.contains("Bulk update completed successfully")) {
completed.countDown();
}
});
- new CommandTester(plugin, executor)
+ new CommandTester(executor, console)
.whenRunCommand("creategroup moderator")
.whenRunCommand("creategroup admin")
.whenRunCommand("user Luck parent add moderator server=survival")
@@ -1084,7 +1087,6 @@ public class CommandsIntegrationTest {
.whenRunCommand("group moderator rename mod")
.clearMessageBuffer()
- .givenHasPermissions("luckperms.bulkupdate")
.whenRunCommand("bulkupdate all update permission group.mod \"permission == group.moderator\"")
.thenExpectStartsWith("[LP] Running bulk update.");
@@ -1113,6 +1115,151 @@ public class CommandsIntegrationTest {
),
notchUser.normalData().asSet()
);
+
+ // test normal players are unable to use
+ new CommandTester(executor)
+ .givenHasPermissions("luckperms.bulkupdate")
+ .whenRunCommand("bulkupdate all update permission group.mod \"permission == group.moderator\"")
+ .thenExpect("[LP] The bulk update command can only be used from the console.");
+ });
+ }
+
+ @Test
+ public void testLogCommands(@TempDir Path tempDir) {
+ Map config = new HashMap<>(CONFIG);
+ config.put("log-notify", "true");
+ config.put("log-synchronously-in-commands", "true");
+
+ TestPluginProvider.use(tempDir, config, (app, bootstrap, plugin) -> {
+ CommandExecutor executor = app.getCommandExecutor();
+
+ UUID luckUniqueId = UUID.fromString("c1d60c50-70b5-4722-8057-87767557e50d");
+
+ plugin.getStorage().savePlayerData(luckUniqueId, "Luck").join();
+ plugin.getStorage().savePlayerData(UUID.fromString("069a79f4-44e9-4726-a5be-fca90e38aaf5"), "Notch").join();
+
+ TestSender testSender = new TestSender();
+ testSender.setUniqueId(luckUniqueId);
+ testSender.setName("Luck");
+
+ new CommandTester(executor, testSender)
+ .whenRunCommand("group default permission set hello");
+
+ new CommandTester(executor)
+ .whenRunCommand("creategroup moderator")
+ .whenRunCommand("creategroup admin")
+ .whenRunCommand("createtrack staff")
+ .whenRunCommand("user Luck parent add moderator server=survival")
+ .whenRunCommand("user Notch parent add moderator")
+ .whenRunCommand("group admin parent add moderator")
+ .whenRunCommand("group moderator rename mod")
+ .whenRunCommand("user Luck permission set test.1")
+ .whenRunCommand("user Luck permission set test.2 false")
+ .whenRunCommand("user Luck permission set test.3 server=survival")
+ .whenRunCommand("user Luck permission settemp test.4 true 1h")
+ .whenRunCommand("user Luck permission settemp test.5 false 2d")
+ .clearMessageBuffer()
+
+ .givenHasPermissions("luckperms.log.userhistory")
+ .whenRunCommand("log userhistory Luck")
+ .thenExpectReplacing("\\ds ago", "1m ago", """
+ [LP] Showing history for user luck (page 1 of 1)
+ [LP] #1 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission settemp test.5 false 2d
+ [LP] #2 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission settemp test.4 true 1h
+ [LP] #3 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission set test.3 true server=survival
+ [LP] #4 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission set test.2 false
+ [LP] #5 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission set test.1 true
+ [LP] #6 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > parent add moderator server=survival
+ """
+ )
+
+ .givenHasPermissions("luckperms.log.grouphistory")
+ .whenRunCommand("log grouphistory admin")
+ .thenExpectReplacing("\\ds ago", "1m ago", """
+ [LP] Showing history for group admin (page 1 of 1)
+ [LP] #1 (1m ago) (StandaloneUser) [G] (admin)
+ [LP] > parent add moderator
+ [LP] #2 (1m ago) (StandaloneUser) [G] (admin)
+ [LP] > create
+ """
+ )
+
+ .givenHasPermissions("luckperms.log.trackhistory")
+ .whenRunCommand("log trackhistory staff")
+ .thenExpectReplacing("\\ds ago", "1m ago", """
+ [LP] Showing history for track staff (page 1 of 1)
+ [LP] #1 (1m ago) (StandaloneUser) [T] (staff)
+ [LP] > create
+ """
+ )
+
+ .givenHasPermissions("luckperms.log.recent")
+ .whenRunCommand("log recent")
+ .thenExpectReplacing("\\ds ago", "1m ago", """
+ [LP] Showing recent actions (page 1 of 2)
+ [LP] #1 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission settemp test.5 false 2d
+ [LP] #2 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission settemp test.4 true 1h
+ [LP] #3 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission set test.3 true server=survival
+ [LP] #4 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission set test.2 false
+ [LP] #5 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > permission set test.1 true
+ [LP] #6 (1m ago) (StandaloneUser) [G] (moderator)
+ [LP] > rename mod
+ [LP] #7 (1m ago) (StandaloneUser) [G] (admin)
+ [LP] > parent add moderator
+ [LP] #8 (1m ago) (StandaloneUser) [U] (notch)
+ [LP] > parent add moderator
+ [LP] #9 (1m ago) (StandaloneUser) [U] (luck)
+ [LP] > parent add moderator server=survival
+ [LP] #10 (1m ago) (StandaloneUser) [T] (staff)
+ [LP] > create
+ """
+ )
+
+ .givenHasPermissions("luckperms.log.recent")
+ .whenRunCommand("log recent 2")
+ .thenExpectReplacing("\\ds ago", "1m ago", """
+ [LP] Showing recent actions (page 2 of 2)
+ [LP] #11 (1m ago) (StandaloneUser) [G] (admin)
+ [LP] > create
+ [LP] #12 (1m ago) (StandaloneUser) [G] (moderator)
+ [LP] > create
+ [LP] #13 (1m ago) (Luck) [G] (default)
+ [LP] > permission set hello true
+ """
+ )
+
+ .givenHasPermissions("luckperms.log.recent")
+ .whenRunCommand("log recent 3")
+ .thenExpect("[LP] Invalid page number. Please enter a value between 1 and 2.")
+
+ .givenHasPermissions("luckperms.log.search")
+ .whenRunCommand("log search hello")
+ .thenExpectReplacing("\\ds ago", "1m ago", """
+ [LP] Showing recent actions for query hello (page 1 of 1)
+ [LP] #1 (1m ago) (Luck) [G] (default)
+ [LP] > permission set hello true
+ """
+ )
+
+ .givenHasPermissions("luckperms.log.recent")
+ .whenRunCommand("log recent Luck")
+ .thenExpectReplacing("\\ds ago", "1m ago", """
+ [LP] Showing recent actions by Luck (page 1 of 1)
+ [LP] #1 (1m ago) (Luck) [G] (default)
+ [LP] > permission set hello true
+ """
+ );
});
}
@@ -1121,7 +1268,7 @@ public class CommandsIntegrationTest {
TestPluginProvider.use(tempDir, CONFIG, (app, bootstrap, plugin) -> {
CommandExecutor executor = app.getCommandExecutor();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.givenHasPermissions("luckperms.user.info")
.whenRunCommand("user unknown info")
.thenExpect("[LP] A user for unknown could not be found.")
@@ -1154,7 +1301,7 @@ public class CommandsIntegrationTest {
CommandExecutor executor = app.getCommandExecutor();
String version = "v" + bootstrap.getVersion();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.givenHasPermissions(/* empty */)
.whenRunCommand("")
@@ -1188,7 +1335,10 @@ public class CommandsIntegrationTest {
// by default, notifications are not sent to the user who initiated the event - override that
app.getApi().getEventBus().subscribe(LogNotifyEvent.class, e -> e.setCancelled(false));
- new CommandTester(plugin, executor)
+ TestSender sender = new TestSender();
+ plugin.addOnlineSender(sender);
+
+ new CommandTester(executor, sender)
.givenHasPermissions("luckperms.group.permission.set", "luckperms.log.notify")
.whenRunCommand("group default permission set hello.world true server=test")
.thenExpect("""
@@ -1208,7 +1358,7 @@ public class CommandsIntegrationTest {
TestPluginProvider.use(tempDir, config, (app, bootstrap, plugin) -> {
CommandExecutor executor = app.getCommandExecutor();
- new CommandTester(plugin, executor)
+ new CommandTester(executor)
.givenHasPermissions("luckperms.group.permission.set")
.whenRunCommand("group default permission set hello.world true server=test")
.thenExpect("[LP] You do not have permission to use this command!")
diff --git a/standalone/src/test/java/me/lucko/luckperms/standalone/WebEditorIntegrationTest.java b/standalone/src/test/java/me/lucko/luckperms/standalone/WebEditorIntegrationTest.java
index 28b43f3b2..1d88138ff 100644
--- a/standalone/src/test/java/me/lucko/luckperms/standalone/WebEditorIntegrationTest.java
+++ b/standalone/src/test/java/me/lucko/luckperms/standalone/WebEditorIntegrationTest.java
@@ -36,7 +36,7 @@ import me.lucko.luckperms.common.util.Predicates;
import me.lucko.luckperms.common.util.gson.GsonProvider;
import me.lucko.luckperms.common.webeditor.WebEditorRequest;
import me.lucko.luckperms.common.webeditor.WebEditorSession;
-import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
+import me.lucko.luckperms.standalone.app.integration.StandaloneUser;
import me.lucko.luckperms.standalone.utils.TestPluginProvider;
import net.luckperms.api.model.data.DataType;
import okhttp3.OkHttpClient;
@@ -115,7 +115,7 @@ public class WebEditorIntegrationTest {
assertFalse(holders.isEmpty());
// create a new editor session
- Sender sender = plugin.getSenderFactory().wrap(SingletonPlayer.INSTANCE);
+ Sender sender = plugin.getSenderFactory().wrap(StandaloneUser.INSTANCE);
WebEditorSession session = WebEditorSession.create(holders, Collections.emptyList(), sender, "lp", plugin);
String bytebinKey = session.open();
String bytesocksKey = session.getSocket().getSocket().channelId();
diff --git a/standalone/src/test/java/me/lucko/luckperms/standalone/utils/CommandTester.java b/standalone/src/test/java/me/lucko/luckperms/standalone/utils/CommandTester.java
index 97d85a0fc..3b9d29f79 100644
--- a/standalone/src/test/java/me/lucko/luckperms/standalone/utils/CommandTester.java
+++ b/standalone/src/test/java/me/lucko/luckperms/standalone/utils/CommandTester.java
@@ -26,14 +26,12 @@
package me.lucko.luckperms.standalone.utils;
import me.lucko.luckperms.standalone.app.integration.CommandExecutor;
-import me.lucko.luckperms.standalone.app.integration.SingletonPlayer;
-import me.lucko.luckperms.standalone.utils.TestPluginBootstrap.TestPlugin;
-import me.lucko.luckperms.standalone.utils.TestPluginBootstrap.TestSenderFactory;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.luckperms.api.util.Tristate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.intellij.lang.annotations.RegExp;
import java.util.ArrayList;
import java.util.Collections;
@@ -57,12 +55,12 @@ public final class CommandTester implements Consumer, Function permissions = null;
@@ -72,9 +70,16 @@ public final class CommandTester implements Consumer, Function messageBuffer = Collections.synchronizedList(new ArrayList<>());
- public CommandTester(TestPlugin plugin, CommandExecutor executor) {
- this.plugin = plugin;
+ public CommandTester(CommandExecutor executor, TestSender sender) {
this.executor = executor;
+ this.sender = sender;
+
+ this.sender.setPermissionChecker(this);
+ this.sender.addMessageSink(this);
+ }
+
+ public CommandTester(CommandExecutor executor) {
+ this(executor, new TestSender());
}
/**
@@ -138,15 +143,7 @@ public final class CommandTester implements Consumer, Function, Function
*
* - Dependency loading system is replaced with a no-op stub that delegates to the test classloader
- * - Sender factory is extended and allows for permission checks to be intercepted
+ * - Ability to register additional sender instances as being online
*
*
*/
@@ -81,7 +79,7 @@ public final class TestPluginBootstrap extends LPStandaloneBootstrap {
}
public static final class TestPlugin extends LPStandalonePlugin {
- private TestSenderFactory senderFactory;
+ private final Set onlineSenders = new CopyOnWriteArraySet<>();
TestPlugin(LPStandaloneBootstrap bootstrap) {
super(bootstrap);
@@ -93,13 +91,15 @@ public final class TestPluginBootstrap extends LPStandaloneBootstrap {
}
@Override
- protected void setupSenderFactory() {
- this.senderFactory = new TestSenderFactory(this);
+ public Stream getOnlineSenders() {
+ return Stream.concat(
+ Stream.of(StandaloneUser.INSTANCE),
+ this.onlineSenders.stream()
+ ).map(player -> getSenderFactory().wrap(player));
}
- @Override
- public TestSenderFactory getSenderFactory() {
- return this.senderFactory;
+ public void addOnlineSender(StandaloneSender player) {
+ this.onlineSenders.add(player);
}
}
@@ -125,46 +125,4 @@ public final class TestPluginBootstrap extends LPStandaloneBootstrap {
}
}
-
- public static final class TestSenderFactory extends StandaloneSenderFactory {
-
- private Function permissionChecker;
-
- public TestSenderFactory(LPStandalonePlugin plugin) {
- super(plugin);
- }
-
- public void setPermissionChecker(Function permissionChecker) {
- this.permissionChecker = permissionChecker;
- }
-
- public void resetPermissionChecker() {
- this.permissionChecker = null;
- }
-
- @Override
- protected boolean consoleHasAllPermissions() {
- return false;
- }
-
- @Override
- protected void sendMessage(SingletonPlayer sender, Component message) {
- Component rendered = TranslationManager.render(message, Locale.ENGLISH);
- sender.sendMessage(rendered);
- }
-
- @Override
- protected Tristate getPermissionValue(SingletonPlayer sender, String node) {
- return this.permissionChecker == null
- ? super.getPermissionValue(sender, node)
- : this.permissionChecker.apply(node);
- }
-
- @Override
- protected boolean hasPermission(SingletonPlayer sender, String node) {
- return this.permissionChecker == null
- ? super.hasPermission(sender, node)
- : this.permissionChecker.apply(node).asBoolean();
- }
- }
}
diff --git a/standalone/src/test/java/me/lucko/luckperms/standalone/utils/TestSender.java b/standalone/src/test/java/me/lucko/luckperms/standalone/utils/TestSender.java
new file mode 100644
index 000000000..e1723dea5
--- /dev/null
+++ b/standalone/src/test/java/me/lucko/luckperms/standalone/utils/TestSender.java
@@ -0,0 +1,113 @@
+/*
+ * This file is part of LuckPerms, licensed under the MIT License.
+ *
+ * Copyright (c) lucko (Luck)
+ * Copyright (c) contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.lucko.luckperms.standalone.utils;
+
+import me.lucko.luckperms.standalone.app.integration.StandaloneSender;
+import me.lucko.luckperms.standalone.app.integration.StandaloneUser;
+import net.kyori.adventure.text.Component;
+import net.luckperms.api.util.Tristate;
+
+import java.util.Locale;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class TestSender implements StandaloneSender {
+
+ private final Set> messageSinks;
+
+ private String name = "StandaloneUser";
+ private UUID uniqueId = UUID.randomUUID();
+ private boolean isConsole = false;
+
+ private Function permissionChecker;
+
+ public TestSender() {
+ this.messageSinks = new CopyOnWriteArraySet<>();
+ this.messageSinks.add(StandaloneUser.INSTANCE::sendMessage);
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public UUID getUniqueId() {
+ return this.uniqueId;
+ }
+
+ public void setUniqueId(UUID uuid) {
+ this.uniqueId = uuid;
+ }
+
+ @Override
+ public void sendMessage(Component component) {
+ for (Consumer sink : this.messageSinks) {
+ sink.accept(component);
+ }
+ }
+
+ @Override
+ public Tristate getPermissionValue(String permission) {
+ return this.permissionChecker == null
+ ? Tristate.TRUE
+ : this.permissionChecker.apply(permission);
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ return getPermissionValue(permission).asBoolean();
+ }
+
+ @Override
+ public boolean isConsole() {
+ return this.isConsole;
+ }
+
+ public void setConsole(boolean console) {
+ this.isConsole = console;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return Locale.ENGLISH;
+ }
+
+ public void setPermissionChecker(Function permissionChecker) {
+ this.permissionChecker = permissionChecker;
+ }
+
+ public void addMessageSink(Consumer sink) {
+ this.messageSinks.add(sink);
+ }
+}