From 9e7a3d26e4992df88e9eb439fc2760c13ca2785e Mon Sep 17 00:00:00 2001
From: lucko
Date: Sun, 16 Jun 2024 21:11:23 +0100
Subject: [PATCH] Improve efficiency of action log queries (#3917)
---
.../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 ++
.../api/event/sync/PostNetworkSyncEvent.java | 1 -
.../java/net/luckperms/api/util/Page.java | 53 +++
.../listeners/BukkitPlatformListener.java | 1 -
common/build.gradle | 11 +-
.../lucko/luckperms/common/actionlog/Log.java | 108 ------
.../common/actionlog/LogDispatcher.java | 68 ++--
.../Paginated.java => actionlog/LogPage.java} | 64 ++--
.../common/actionlog/LoggedAction.java | 23 +-
.../common/actionlog/filter/ActionFields.java | 60 +++
.../filter/ActionFilterMongoBuilder.java | 70 ++++
.../filter/ActionFilterSqlBuilder.java | 69 ++++
.../actionlog/filter/ActionFilters.java | 110 ++++++
.../common/api/LuckPermsApiProvider.java | 6 +
.../api/implementation/ApiActionFilter.java | 47 +++
.../ApiActionFilterFactory.java | 77 ++++
.../api/implementation/ApiActionLog.java | 35 +-
.../api/implementation/ApiActionLogger.java | 61 ++-
.../common/bulkupdate/BulkUpdate.java | 87 +----
.../common/bulkupdate/BulkUpdateBuilder.java | 25 +-
.../common/bulkupdate/BulkUpdateField.java | 68 ++++
.../bulkupdate/BulkUpdateSqlBuilder.java | 76 ++++
.../{Action.java => BulkUpdateAction.java} | 14 +-
.../bulkupdate/action/DeleteAction.java | 8 +-
.../bulkupdate/action/UpdateAction.java | 39 +-
.../comparison/StandardComparison.java | 112 ------
.../common/bulkupdate/query/Query.java | 83 ----
.../command/abstraction/ParentCommand.java | 69 ++--
.../common/commands/group/DeleteGroup.java | 8 +-
.../commands/group/GroupParentCommand.java | 2 +-
.../common/commands/group/GroupRename.java | 10 +-
.../common/commands/log/LogGroupHistory.java | 33 +-
.../common/commands/log/LogNotify.java | 5 +-
.../common/commands/log/LogParentCommand.java | 47 +--
.../common/commands/log/LogRecent.java | 67 ++--
.../common/commands/log/LogSearch.java | 35 +-
.../common/commands/log/LogTrackHistory.java | 34 +-
.../common/commands/log/LogUserHistory.java | 29 +-
.../commands/misc/BulkUpdateCommand.java | 22 +-
.../common/commands/misc/SearchCommand.java | 12 +-
.../commands/track/TrackParentCommand.java | 2 +-
.../commands/user/UserParentCommand.java | 2 +-
.../luckperms/common/config/ConfigKeys.java | 5 +
.../comparison => filter}/Comparison.java | 66 ++--
.../comparison => filter}/Constraint.java | 42 +-
.../common/filter/ConstraintFactory.java | 102 +++++
.../lucko/luckperms/common/filter/Filter.java | 59 +++
.../luckperms/common/filter/FilterField.java | 74 ++++
.../luckperms/common/filter/FilterList.java | 101 +++++
.../common/filter/PageParameters.java | 79 ++++
.../filter/mongo/ConstraintMongoBuilder.java | 87 +++++
.../filter/mongo/FilterMongoBuilder.java | 65 ++++
.../filter/sql/ConstraintSqlBuilder.java | 84 ++++
.../common/filter/sql/FilterSqlBuilder.java | 81 ++++
.../luckperms/common/locale/Message.java | 4 +-
.../messaging/InternalMessagingService.java | 10 +-
.../messaging/LuckPermsMessagingService.java | 23 +-
.../node/matcher/ConstraintNodeMatcher.java | 14 +-
.../node/matcher/StandardNodeMatchers.java | 39 +-
.../common/sender/AbstractSender.java | 6 +-
.../common/sender/SenderFactory.java | 4 +-
.../luckperms/common/storage/Storage.java | 42 +-
.../implementation/StorageImplementation.java | 6 +-
.../file/AbstractConfigurateStorage.java | 9 +-
.../implementation/file/FileActionLogger.java | 33 +-
.../implementation/mongodb/MongoStorage.java | 191 ++++-----
.../implementation/split/SplitStorage.java | 9 +-
.../implementation/sql/SqlStorage.java | 98 +++--
.../sql/builder/AbstractSqlBuilder.java | 36 ++
.../builder}/PreparedStatementBuilder.java | 25 +-
.../storage/misc/StorageCredentials.java | 6 +
.../luckperms/common/util/AsyncInterface.java | 71 ++++
.../actionlog/ActionFilterMongoTest.java | 89 +++++
.../common/actionlog/ActionFilterSqlTest.java | 83 ++++
.../common/actionlog/ActionFilterTest.java | 226 +++++++++++
.../common/bulkupdate/BulkUpdateSqlTest.java | 143 +++++++
.../common/bulkupdate/BulkUpdateTest.java | 90 +----
.../ComparisonTest.java | 13 +-
.../common/filter/FilterMongoTest.java | 118 ++++++
.../common/filter/FilterSqlTest.java | 115 ++++++
.../common/filter/PageParametersTest.java | 50 +++
.../common/storage/AbstractStorageTest.java | 361 ++++++++++++++++++
.../storage/ConfigurateStorageTest.java | 141 +++++++
.../common/storage/MongoStorageTest.java | 61 +++
.../common/storage/SqlStorageTest.java | 226 +----------
.../luckperms/common/util/PaginatedTest.java | 104 -----
.../listeners/FabricConnectionListener.java | 1 -
.../messaging/PluginMessageMessenger.java | 3 -
.../luckperms/fabric/model/MixinUser.java | 2 -
.../app/integration/CommandExecutor.java | 12 +-
.../app/integration/StandaloneSender.java | 36 +-
...ngletonPlayer.java => StandaloneUser.java} | 55 ++-
.../standalone/LPStandalonePlugin.java | 4 +-
.../standalone/StandaloneCommandManager.java | 10 +-
.../standalone/StandaloneSenderFactory.java | 45 ++-
.../stub/StandaloneContextManager.java | 24 +-
.../standalone/CommandsIntegrationTest.java | 204 ++++++++--
.../standalone/StorageIntegrationTest.java | 6 +-
.../standalone/WebEditorIntegrationTest.java | 4 +-
.../standalone/utils/CommandTester.java | 48 ++-
.../standalone/utils/TestPluginBootstrap.java | 70 +---
.../standalone/utils/TestSender.java | 113 ++++++
108 files changed, 4363 insertions(+), 1640 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
delete mode 100644 common/src/main/java/me/lucko/luckperms/common/actionlog/Log.java
rename common/src/main/java/me/lucko/luckperms/common/{util/Paginated.java => actionlog/LogPage.java} (66%)
create mode 100644 common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFields.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilterMongoBuilder.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilterSqlBuilder.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilters.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/bulkupdate/BulkUpdateField.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateSqlBuilder.java
rename common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/{Action.java => BulkUpdateAction.java} (80%)
delete mode 100644 common/src/main/java/me/lucko/luckperms/common/bulkupdate/comparison/StandardComparison.java
delete mode 100644 common/src/main/java/me/lucko/luckperms/common/bulkupdate/query/Query.java
rename common/src/main/java/me/lucko/luckperms/common/{bulkupdate/comparison => filter}/Comparison.java (56%)
rename common/src/main/java/me/lucko/luckperms/common/{bulkupdate/comparison => filter}/Constraint.java (60%)
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/ConstraintFactory.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/Filter.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/FilterField.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/FilterList.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/PageParameters.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/mongo/ConstraintMongoBuilder.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/mongo/FilterMongoBuilder.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/sql/ConstraintSqlBuilder.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/filter/sql/FilterSqlBuilder.java
create mode 100644 common/src/main/java/me/lucko/luckperms/common/storage/implementation/sql/builder/AbstractSqlBuilder.java
rename common/src/main/java/me/lucko/luckperms/common/{bulkupdate => storage/implementation/sql/builder}/PreparedStatementBuilder.java (75%)
create mode 100644 common/src/main/java/me/lucko/luckperms/common/util/AsyncInterface.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/actionlog/ActionFilterMongoTest.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/actionlog/ActionFilterSqlTest.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/actionlog/ActionFilterTest.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateSqlTest.java
rename common/src/test/java/me/lucko/luckperms/common/{bulkupdate => filter}/ComparisonTest.java (77%)
create mode 100644 common/src/test/java/me/lucko/luckperms/common/filter/FilterMongoTest.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/filter/FilterSqlTest.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/filter/PageParametersTest.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/storage/AbstractStorageTest.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/storage/ConfigurateStorageTest.java
create mode 100644 common/src/test/java/me/lucko/luckperms/common/storage/MongoStorageTest.java
delete mode 100644 common/src/test/java/me/lucko/luckperms/common/util/PaginatedTest.java
rename common/src/main/java/me/lucko/luckperms/common/bulkupdate/query/QueryField.java => standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/StandaloneSender.java (68%)
rename standalone/app/src/main/java/me/lucko/luckperms/standalone/app/integration/{SingletonPlayer.java => StandaloneUser.java} (56%)
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/event/sync/PostNetworkSyncEvent.java b/api/src/main/java/net/luckperms/api/event/sync/PostNetworkSyncEvent.java
index 34dc3f66a..c156eb0ce 100644
--- a/api/src/main/java/net/luckperms/api/event/sync/PostNetworkSyncEvent.java
+++ b/api/src/main/java/net/luckperms/api/event/sync/PostNetworkSyncEvent.java
@@ -26,7 +26,6 @@
package net.luckperms.api.event.sync;
import net.luckperms.api.event.LuckPermsEvent;
-import net.luckperms.api.event.type.Cancellable;
import net.luckperms.api.event.util.Param;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
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/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitPlatformListener.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitPlatformListener.java
index 977001b6c..9e599a304 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitPlatformListener.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/listeners/BukkitPlatformListener.java
@@ -37,7 +37,6 @@ import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.event.server.RemoteServerCommandEvent;
import org.bukkit.event.server.ServerCommandEvent;
-import java.util.Locale;
import java.util.regex.Pattern;
public class BukkitPlatformListener implements Listener {
diff --git a/common/build.gradle b/common/build.gradle
index d3e5e9966..9db5a047f 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -4,7 +4,11 @@ plugins {
}
test {
- useJUnitPlatform {}
+ useJUnitPlatform {
+ if (!project.hasProperty('dockerTests')) {
+ excludeTags 'docker'
+ }
+ }
}
jacocoTestReport {
@@ -15,9 +19,14 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.1'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.1'
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.1'
+ testImplementation "org.testcontainers:junit-jupiter:1.19.8"
testImplementation 'org.mockito:mockito-core:5.11.0'
testImplementation 'org.mockito:mockito-junit-jupiter:5.11.0'
testImplementation 'com.h2database:h2:2.1.214'
+ testImplementation 'org.mongodb:mongodb-driver-legacy:4.5.0'
+ testImplementation 'org.spongepowered:configurate-yaml:3.7.2'
+ testImplementation 'org.spongepowered:configurate-hocon:3.7.2'
+ testImplementation 'me.lucko.configurate:configurate-toml:3.7'
api project(':api')
api 'org.checkerframework:checker-qual:3.12.0'
diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/Log.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/Log.java
deleted file mode 100644
index f5c744988..000000000
--- a/common/src/main/java/me/lucko/luckperms/common/actionlog/Log.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.actionlog;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSortedSet;
-import me.lucko.luckperms.common.util.ImmutableCollectors;
-import net.luckperms.api.actionlog.Action;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.UUID;
-
-public class Log {
- private static final Log EMPTY = new Log(ImmutableList.of());
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static Log empty() {
- return EMPTY;
- }
-
- private final SortedSet content;
-
- Log(List content) {
- this.content = ImmutableSortedSet.copyOf(content);
- }
-
- public SortedSet getContent() {
- return this.content;
- }
-
- public SortedSet getContent(UUID actor) {
- return this.content.stream()
- .filter(e -> e.getSource().getUniqueId().equals(actor))
- .collect(ImmutableCollectors.toSortedSet());
- }
-
- public SortedSet getUserHistory(UUID uniqueId) {
- return this.content.stream()
- .filter(e -> e.getTarget().getType() == Action.Target.Type.USER)
- .filter(e -> e.getTarget().getUniqueId().isPresent() && e.getTarget().getUniqueId().get().equals(uniqueId))
- .collect(ImmutableCollectors.toSortedSet());
- }
-
- public SortedSet getGroupHistory(String name) {
- return this.content.stream()
- .filter(e -> e.getTarget().getType() == Action.Target.Type.GROUP)
- .filter(e -> e.getTarget().getName().equals(name))
- .collect(ImmutableCollectors.toSortedSet());
- }
-
- public SortedSet getTrackHistory(String name) {
- return this.content.stream()
- .filter(e -> e.getTarget().getType() == Action.Target.Type.TRACK)
- .filter(e -> e.getTarget().getName().equals(name))
- .collect(ImmutableCollectors.toSortedSet());
- }
-
- public SortedSet getSearch(String query) {
- return this.content.stream()
- .filter(e -> e.matchesSearch(query))
- .collect(ImmutableCollectors.toSortedSet());
- }
-
- public static class Builder {
- private final List content = new ArrayList<>();
-
- public Builder add(LoggedAction e) {
- this.content.add(e);
- return this;
- }
-
- public Log build() {
- if (this.content.isEmpty()) {
- return EMPTY;
- }
- return new Log(this.content);
- }
- }
-
-}
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/util/Paginated.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/LogPage.java
similarity index 66%
rename from common/src/main/java/me/lucko/luckperms/common/util/Paginated.java
rename to common/src/main/java/me/lucko/luckperms/common/actionlog/LogPage.java
index 7feb91712..b9ea7c008 100644
--- a/common/src/main/java/me/lucko/luckperms/common/util/Paginated.java
+++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/LogPage.java
@@ -23,54 +23,50 @@
* SOFTWARE.
*/
-package me.lucko.luckperms.common.util;
+package me.lucko.luckperms.common.actionlog;
import com.google.common.collect.ImmutableList;
+import me.lucko.luckperms.common.filter.PageParameters;
+import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.Objects;
-/**
- * A simple pagination utility
- *
- * @param the element type
- */
-public class Paginated {
- private final List content;
-
- public Paginated(Collection content) {
- this.content = ImmutableList.copyOf(content);
+public class LogPage {
+ public static LogPage of(List content, @Nullable PageParameters params, int totalEntries) {
+ return new LogPage(content, params, totalEntries);
}
- public List getContent() {
+ private final List content;
+ private final @Nullable PageParameters params;
+ private final int totalEntries;
+
+ LogPage(List content, @Nullable PageParameters params, int totalEntries) {
+ this.content = ImmutableList.copyOf(content);
+ this.params = params;
+ this.totalEntries = totalEntries;
+ }
+
+ public List getContent() {
return this.content;
}
- public int getMaxPages(int entriesPerPage) {
- return (int) Math.ceil((double) this.content.size() / (double) entriesPerPage);
+ public List> getNumberedContent() {
+ int startIndex = this.params != null
+ ? this.params.pageSize() * (this.params.pageNumber() - 1)
+ : 0;
+
+ List> numberedContent = new ArrayList<>();
+ for (int i = 0; i < this.content.size(); i++) {
+ int index = startIndex + i + 1;
+ numberedContent.add(new Entry<>(index, this.content.get(i)));
+ }
+ return numberedContent;
}
- public List> getPage(int pageNo, int pageSize) {
- if (pageNo < 1) {
- throw new IllegalArgumentException("pageNo cannot be less than 1: " + pageNo);
- }
-
- int first = (pageNo - 1) * pageSize;
- if (this.content.size() <= first) {
- throw new IllegalStateException("Content does not contain that many elements. (requested page: " + pageNo +
- ", page size: " + pageSize + ", page first index: " + first + ", content size: " + this.content.size() + ")");
- }
-
- int last = first + pageSize - 1;
- List> out = new ArrayList<>(pageSize);
-
- for (int i = first; i <= last && i < this.content.size(); i++) {
- out.add(new Entry<>(i + 1, this.content.get(i)));
- }
-
- return out;
+ public int getTotalEntries() {
+ return this.totalEntries;
}
public static final class Entry {
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 defeb575c..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
@@ -393,14 +390,14 @@ public class LoggedAction implements Action {
}
}
- public static char getTypeCharacter(Target.Type type) {
+ public static String getTypeString(Target.Type type) {
switch (type) {
case USER:
- return 'U';
+ return "U";
case GROUP:
- return 'G';
+ return "G";
case TRACK:
- return 'T';
+ return "T";
default:
throw new AssertionError();
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFields.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFields.java
new file mode 100644
index 000000000..b4887e701
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFields.java
@@ -0,0 +1,60 @@
+/*
+ * 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.actionlog.filter;
+
+import me.lucko.luckperms.common.filter.FilterField;
+import net.luckperms.api.actionlog.Action;
+
+import java.util.UUID;
+
+public final class ActionFields {
+
+ public static final FilterField SOURCE_UNIQUE_ID = FilterField.named(
+ "SOURCE_UNIQUE_ID",
+ action -> action.getSource().getUniqueId()
+ );
+ public static final FilterField SOURCE_NAME = FilterField.named(
+ "SOURCE_NAME",
+ action -> action.getSource().getName()
+ );
+ public static final FilterField TARGET_TYPE = FilterField.named(
+ "TARGET_TYPE",
+ action -> action.getTarget().getType()
+ );
+ public static final FilterField TARGET_UNIQUE_ID = FilterField.named(
+ "TARGET_UNIQUE_ID",
+ action -> action.getTarget().getUniqueId().orElse(null)
+ );
+ public static final FilterField TARGET_NAME = FilterField.named(
+ "TARGET_NAME",
+ action -> action.getTarget().getName()
+ );
+ public static final FilterField DESCRIPTION = FilterField.named(
+ "DESCRIPTION",
+ action -> action.getDescription()
+ );
+
+}
\ No newline at end of file
diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilterMongoBuilder.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilterMongoBuilder.java
new file mode 100644
index 000000000..d82ec017e
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilterMongoBuilder.java
@@ -0,0 +1,70 @@
+/*
+ * 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.actionlog.filter;
+
+import me.lucko.luckperms.common.filter.FilterField;
+import me.lucko.luckperms.common.filter.mongo.FilterMongoBuilder;
+import net.luckperms.api.actionlog.Action;
+
+import java.util.UUID;
+
+public final class ActionFilterMongoBuilder extends FilterMongoBuilder {
+ public static final ActionFilterMongoBuilder INSTANCE = new ActionFilterMongoBuilder();
+
+ private ActionFilterMongoBuilder() {
+
+ }
+
+ @Override
+ public String mapFieldName(FilterField field) {
+ if (field == ActionFields.SOURCE_UNIQUE_ID) {
+ return "source.uniqueId";
+ } else if (field == ActionFields.SOURCE_NAME) {
+ return "source.name";
+ } else if (field == ActionFields.TARGET_TYPE) {
+ return "target.type";
+ } else if (field == ActionFields.TARGET_UNIQUE_ID) {
+ return "target.uniqueId";
+ } else if (field == ActionFields.TARGET_NAME) {
+ return "target.name";
+ } else if (field == ActionFields.DESCRIPTION) {
+ return "description";
+ }
+ throw new AssertionError(field);
+ }
+
+ @Override
+ public Object mapConstraintValue(Object value) {
+ if (value instanceof String | value instanceof UUID) {
+ return value;
+ } else if (value instanceof Action.Target.Type) {
+ return ((Action.Target.Type) value).name();
+ } else {
+ throw new IllegalArgumentException("Don't know how to map value with type: " + value.getClass().getName());
+ }
+ }
+
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilterSqlBuilder.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilterSqlBuilder.java
new file mode 100644
index 000000000..e7a71ce9a
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilterSqlBuilder.java
@@ -0,0 +1,69 @@
+/*
+ * 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.actionlog.filter;
+
+import me.lucko.luckperms.common.actionlog.LoggedAction;
+import me.lucko.luckperms.common.filter.FilterField;
+import me.lucko.luckperms.common.filter.sql.FilterSqlBuilder;
+import net.luckperms.api.actionlog.Action;
+
+import java.util.UUID;
+
+public class ActionFilterSqlBuilder extends FilterSqlBuilder {
+
+ @Override
+ public void visitFieldName(FilterField field) {
+ if (field == ActionFields.SOURCE_UNIQUE_ID) {
+ this.builder.append("actor_uuid");
+ } else if (field == ActionFields.SOURCE_NAME) {
+ this.builder.append("actor_name");
+ } else if (field == ActionFields.TARGET_TYPE) {
+ this.builder.append("type");
+ } else if (field == ActionFields.TARGET_UNIQUE_ID) {
+ this.builder.append("acted_uuid");
+ } else if (field == ActionFields.TARGET_NAME) {
+ this.builder.append("acted_name");
+ } else if (field == ActionFields.DESCRIPTION) {
+ this.builder.append("action");
+ } else {
+ throw new AssertionError(field);
+ }
+ }
+
+ @Override
+ public void visitConstraintValue(Object value) {
+ if (value instanceof String) {
+ this.builder.variable(((String) value));
+ } else if (value instanceof UUID) {
+ this.builder.variable(value.toString());
+ } else if (value instanceof Action.Target.Type) {
+ this.builder.variable(LoggedAction.getTypeString((Action.Target.Type) value));
+ } else {
+ throw new IllegalArgumentException("Don't know how to write value with type: " + value.getClass().getName());
+ }
+ }
+
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilters.java b/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilters.java
new file mode 100644
index 000000000..f1513a2ca
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/actionlog/filter/ActionFilters.java
@@ -0,0 +1,110 @@
+/*
+ * 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.actionlog.filter;
+
+import me.lucko.luckperms.common.filter.Comparison;
+import me.lucko.luckperms.common.filter.ConstraintFactory;
+import me.lucko.luckperms.common.filter.FilterList;
+import net.luckperms.api.actionlog.Action;
+import net.luckperms.api.actionlog.Action.Target;
+
+import java.util.UUID;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+
+public final class ActionFilters {
+ private ActionFilters() {}
+
+ // all actions
+ public static FilterList all() {
+ return FilterList.empty();
+ }
+
+ // all actions performed by a given source (actor)
+ public static FilterList source(UUID uniqueId) {
+ return FilterList.and(
+ ActionFields.SOURCE_UNIQUE_ID.isEqualTo(uniqueId, ConstraintFactory.UUIDS)
+ );
+ }
+
+ // all actions affecting a given user
+ public static FilterList user(UUID uniqueId) {
+ return FilterList.and(
+ ActionFields.TARGET_TYPE.isEqualTo(Target.Type.USER, TARGET_TYPE_CONSTRAINT_FACTORY),
+ ActionFields.TARGET_UNIQUE_ID.isEqualTo(uniqueId, ConstraintFactory.UUIDS)
+ );
+ }
+
+ // all actions affecting a given group
+ public static FilterList group(String name) {
+ return FilterList.and(
+ ActionFields.TARGET_TYPE.isEqualTo(Target.Type.GROUP, TARGET_TYPE_CONSTRAINT_FACTORY),
+ ActionFields.TARGET_NAME.isEqualTo(name, ConstraintFactory.STRINGS)
+ );
+ }
+
+ // all actions affecting a given track
+ public static FilterList track(String name) {
+ return FilterList.and(
+ ActionFields.TARGET_TYPE.isEqualTo(Target.Type.TRACK, TARGET_TYPE_CONSTRAINT_FACTORY),
+ ActionFields.TARGET_NAME.isEqualTo(name, ConstraintFactory.STRINGS)
+ );
+ }
+
+ // all actions matching the given search query
+ public static FilterList search(String query) {
+ return FilterList.or(
+ ActionFields.SOURCE_NAME.isSimilarTo("%" + query + "%", ConstraintFactory.STRINGS),
+ ActionFields.TARGET_NAME.isSimilarTo("%" + query + "%", ConstraintFactory.STRINGS),
+ ActionFields.DESCRIPTION.isSimilarTo("%" + query + "%", ConstraintFactory.STRINGS)
+ );
+ }
+
+ private static final ConstraintFactory TARGET_TYPE_CONSTRAINT_FACTORY = new ConstraintFactory() {
+ @Override
+ public Predicate equal(Target.Type value) {
+ return value::equals;
+ }
+
+ @Override
+ public Predicate notEqual(Target.Type value) {
+ return string -> !value.equals(string);
+ }
+
+ @Override
+ public Predicate similar(Target.Type value) {
+ Pattern pattern = Comparison.compilePatternForLikeSyntax(value.toString());
+ return type -> pattern.matcher(type.toString()).matches();
+ }
+
+ @Override
+ public Predicate notSimilar(Target.Type value) {
+ Pattern pattern = Comparison.compilePatternForLikeSyntax(value.toString());
+ return type -> !pattern.matcher(type.toString()).matches();
+ }
+ };
+
+}
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 6bacec94e..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
@@ -25,50 +25,63 @@
package me.lucko.luckperms.common.api.implementation;
-import me.lucko.luckperms.common.actionlog.Log;
-import me.lucko.luckperms.common.api.ApiUtils;
+import com.google.common.collect.ImmutableSortedSet;
+import me.lucko.luckperms.common.actionlog.LoggedAction;
+import me.lucko.luckperms.common.util.ImmutableCollectors;
import net.luckperms.api.actionlog.Action;
import net.luckperms.api.actionlog.ActionLog;
import org.checkerframework.checker.nullness.qual.NonNull;
+import java.util.List;
import java.util.Objects;
import java.util.SortedSet;
import java.util.UUID;
-@SuppressWarnings({"unchecked", "rawtypes"})
+@Deprecated
public class ApiActionLog implements ActionLog {
- private final Log handle;
+ private final SortedSet content;
- public ApiActionLog(Log handle) {
- this.handle = handle;
+ public ApiActionLog(List content) {
+ this.content = ImmutableSortedSet.copyOf(content);
}
@Override
public @NonNull SortedSet getContent() {
- return (SortedSet) this.handle.getContent();
+ return this.content;
}
@Override
public @NonNull SortedSet getContent(@NonNull UUID actor) {
Objects.requireNonNull(actor, "actor");
- return (SortedSet) this.handle.getContent(actor);
+ return this.content.stream()
+ .filter(e -> e.getSource().getUniqueId().equals(actor))
+ .collect(ImmutableCollectors.toSortedSet());
}
@Override
public @NonNull SortedSet getUserHistory(@NonNull UUID uniqueId) {
Objects.requireNonNull(uniqueId, "uuid");
- return (SortedSet) this.handle.getUserHistory(uniqueId);
+ return this.content.stream()
+ .filter(e -> e.getTarget().getType() == Action.Target.Type.USER)
+ .filter(e -> e.getTarget().getUniqueId().isPresent() && e.getTarget().getUniqueId().get().equals(uniqueId))
+ .collect(ImmutableCollectors.toSortedSet());
}
@Override
public @NonNull SortedSet getGroupHistory(@NonNull String name) {
Objects.requireNonNull(name, "name");
- return (SortedSet) this.handle.getGroupHistory(ApiUtils.checkName(name));
+ return this.content.stream()
+ .filter(e -> e.getTarget().getType() == Action.Target.Type.GROUP)
+ .filter(e -> e.getTarget().getName().equals(name))
+ .collect(ImmutableCollectors.toSortedSet());
}
@Override
public @NonNull SortedSet getTrackHistory(@NonNull String name) {
Objects.requireNonNull(name, "name");
- return (SortedSet) this.handle.getTrackHistory(ApiUtils.checkName(name));
+ return this.content.stream()
+ .filter(e -> e.getTarget().getType() == Action.Target.Type.TRACK)
+ .filter(e -> e.getTarget().getName().equals(name))
+ .collect(ImmutableCollectors.toSortedSet());
}
}
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 b596e1793..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,13 +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 {
@@ -47,22 +56,66 @@ public class ApiActionLogger implements ActionLogger {
}
@Override
+ @Deprecated
public @NonNull CompletableFuture getLog() {
- return this.plugin.getStorage().getLog().thenApply(ApiActionLog::new);
+ 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/BulkUpdate.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdate.java
index 33375355d..5740ccde1 100644
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdate.java
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdate.java
@@ -25,14 +25,13 @@
package me.lucko.luckperms.common.bulkupdate;
-import me.lucko.luckperms.common.bulkupdate.action.Action;
-import me.lucko.luckperms.common.bulkupdate.query.Query;
+import me.lucko.luckperms.common.bulkupdate.action.BulkUpdateAction;
+import me.lucko.luckperms.common.filter.FilterList;
import me.lucko.luckperms.common.model.HolderType;
import net.luckperms.api.node.Node;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.HashSet;
-import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -46,35 +45,30 @@ public final class BulkUpdate {
private final DataType dataType;
// the action to apply to the data which matches the constraints
- private final Action action;
+ private final BulkUpdateAction action;
- // a set of constraints which data must match to be acted upon
- private final List queries;
+ // a set of filters which data must match to be acted upon
+ private final FilterList filters;
// update statistics of the operation (number of nodes, users and groups affected)
private final BulkUpdateStatistics statistics = new BulkUpdateStatistics();
private final boolean trackStatistics;
- public BulkUpdate(DataType dataType, Action action, List queries, boolean trackStatistics) {
+ public BulkUpdate(DataType dataType, BulkUpdateAction action, FilterList filters, boolean trackStatistics) {
this.dataType = dataType;
this.action = action;
- this.queries = queries;
+ this.filters = filters;
this.trackStatistics = trackStatistics;
}
/**
- * Check to see if a Node instance satisfies the constrints of this query
+ * Check to see if a Node instance satisfies the constraints of this query
*
* @param node the node to check
* @return true if satisfied
*/
- public boolean satisfiesConstraints(Node node) {
- for (Query query : this.queries) {
- if (!query.isSatisfiedBy(node)) {
- return false;
- }
- }
- return true;
+ public boolean satisfiesFilters(Node node) {
+ return this.filters.evaluate(node);
}
/**
@@ -84,7 +78,7 @@ public final class BulkUpdate {
* @return the transformed node, or null if the node should be deleted
*/
private Node apply(Node node) {
- if (!satisfiesConstraints(node)) {
+ if (!satisfiesFilters(node)) {
return node; // make no change
}
@@ -129,63 +123,16 @@ public final class BulkUpdate {
return results;
}
- /**
- * Converts this {@link BulkUpdate} to SQL syntax
- *
- * @return this query in SQL form
- */
- public PreparedStatementBuilder buildAsSql() {
- // DELETE FROM {table} WHERE ...
- // UPDATE {table} SET ... WHERE ...
-
- PreparedStatementBuilder builder = new PreparedStatementBuilder();
-
- // add the action
- // (DELETE FROM or UPDATE)
- this.action.appendSql(builder);
-
- return appendConstraintsAsSql(builder);
- }
-
- /**
- * Appends the constraints of this {@link BulkUpdate} to the provided statement builder in SQL syntax
- *
- * @param builder the statement builder to append the constraints to
- * @return the same statement builder provided as input
- */
- public PreparedStatementBuilder appendConstraintsAsSql(PreparedStatementBuilder builder) {
-
- // if there are no constraints, just return without a WHERE clause
- if (this.queries.isEmpty()) {
- return builder;
- }
-
- // append constraints
- builder.append(" WHERE");
- for (int i = 0; i < this.queries.size(); i++) {
- Query query = this.queries.get(i);
-
- builder.append(" ");
- if (i != 0) {
- builder.append("AND ");
- }
-
- query.appendSql(builder);
- }
-
- return builder;
- }
-
public DataType getDataType() {
return this.dataType;
}
- public Action getAction() {
+ public BulkUpdateAction getAction() {
return this.action;
}
- public List getQueries() {
- return this.queries;
+ public FilterList getFilters() {
+ return this.filters;
}
public boolean isTrackingStatistics() {
@@ -204,12 +151,12 @@ public final class BulkUpdate {
return this.getDataType() == that.getDataType() &&
Objects.equals(this.getAction(), that.getAction()) &&
- Objects.equals(this.getQueries(), that.getQueries());
+ Objects.equals(this.getFilters(), that.getFilters());
}
@Override
public int hashCode() {
- return Objects.hash(getDataType(), getAction(), getQueries(), isTrackingStatistics());
+ return Objects.hash(getDataType(), getAction(), getFilters(), isTrackingStatistics());
}
@Override
@@ -217,7 +164,7 @@ public final class BulkUpdate {
return "BulkUpdate(" +
"dataType=" + this.getDataType() + ", " +
"action=" + this.getAction() + ", " +
- "constraints=" + this.getQueries() + ", " +
+ "constraints=" + this.getFilters() + ", " +
"trackStatistics=" + this.isTrackingStatistics() + ")";
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateBuilder.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateBuilder.java
index 3203e80ac..0e7109bd2 100644
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateBuilder.java
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateBuilder.java
@@ -26,8 +26,12 @@
package me.lucko.luckperms.common.bulkupdate;
import com.google.common.collect.ImmutableList;
-import me.lucko.luckperms.common.bulkupdate.action.Action;
-import me.lucko.luckperms.common.bulkupdate.query.Query;
+import me.lucko.luckperms.common.bulkupdate.action.BulkUpdateAction;
+import me.lucko.luckperms.common.filter.Comparison;
+import me.lucko.luckperms.common.filter.ConstraintFactory;
+import me.lucko.luckperms.common.filter.Filter;
+import me.lucko.luckperms.common.filter.FilterList;
+import net.luckperms.api.node.Node;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -45,18 +49,18 @@ public class BulkUpdateBuilder {
private DataType dataType = DataType.ALL;
// the action to apply to the data which matches the constraints
- private Action action = null;
+ private BulkUpdateAction action = null;
// should the operation count the number of affected nodes, users and groups
private boolean trackStatistics = false;
- // a set of constraints which data must match to be acted upon
- private final Set queries = new LinkedHashSet<>();
+ // a set of filters which data must match to be acted upon
+ private final Set> filters = new LinkedHashSet<>();
private BulkUpdateBuilder() {
}
- public BulkUpdateBuilder action(Action action) {
+ public BulkUpdateBuilder action(BulkUpdateAction action) {
this.action = action;
return this;
}
@@ -71,8 +75,8 @@ public class BulkUpdateBuilder {
return this;
}
- public BulkUpdateBuilder query(Query query) {
- this.queries.add(query);
+ public BulkUpdateBuilder filter(BulkUpdateField field, Comparison comparison, String value) {
+ this.filters.add(new Filter<>(field, ConstraintFactory.STRINGS.build(comparison, value)));
return this;
}
@@ -81,7 +85,8 @@ public class BulkUpdateBuilder {
throw new IllegalStateException("no action specified");
}
- return new BulkUpdate(this.dataType, this.action, ImmutableList.copyOf(this.queries), this.trackStatistics);
+ FilterList filters = new FilterList<>(FilterList.LogicalOperator.AND, ImmutableList.copyOf(this.filters));
+ return new BulkUpdate(this.dataType, this.action, filters, this.trackStatistics);
}
@Override
@@ -89,7 +94,7 @@ public class BulkUpdateBuilder {
return "BulkUpdateBuilder(" +
"dataType=" + this.dataType + ", " +
"action=" + this.action + ", " +
- "constraints=" + this.queries + ", " +
+ "constraints=" + this.filters + ", " +
"trackStatistics=" + this.trackStatistics + ")";
}
}
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
new file mode 100644
index 000000000..03d674e03
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateField.java
@@ -0,0 +1,68 @@
+/*
+ * 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;
+import net.luckperms.api.context.DefaultContextKeys;
+import net.luckperms.api.node.Node;
+
+import java.util.Locale;
+
+/**
+ * Represents a field being used in a bulk update
+ */
+public enum BulkUpdateField implements FilterField {
+
+ PERMISSION {
+ @Override
+ public String getValue(Node node) {
+ return node.getKey();
+ }
+ },
+
+ SERVER {
+ @Override
+ public String getValue(Node node) {
+ return node.getContexts().getAnyValue(DefaultContextKeys.SERVER_KEY).orElse("global");
+ }
+ },
+
+ WORLD {
+ @Override
+ public String getValue(Node node) {
+ return node.getContexts().getAnyValue(DefaultContextKeys.WORLD_KEY).orElse("global");
+ }
+ };
+
+ public static BulkUpdateField of(String s) {
+ try {
+ return valueOf(s.toUpperCase(Locale.ROOT));
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ }
+
+}
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
new file mode 100644
index 000000000..63b25c200
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/BulkUpdateSqlBuilder.java
@@ -0,0 +1,76 @@
+/*
+ * 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.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.FilterField;
+import me.lucko.luckperms.common.filter.sql.FilterSqlBuilder;
+import net.luckperms.api.node.Node;
+
+public class BulkUpdateSqlBuilder extends FilterSqlBuilder {
+
+ public void visit(BulkUpdate update) {
+ visit(update.getAction());
+ visit(update.getFilters());
+ }
+
+ public void visit(BulkUpdateAction action) {
+ if (action instanceof UpdateAction) {
+ visit(((UpdateAction) action));
+ } else if (action instanceof DeleteAction) {
+ visit(((DeleteAction) action));
+ } else {
+ throw new UnsupportedOperationException(action.getClass().getName());
+ }
+ }
+
+ public void visit(UpdateAction action) {
+ this.builder.append("UPDATE {table} SET ");
+ visitFieldName(action.getField());
+ this.builder.append("=");
+ this.builder.variable(action.getNewValue());
+ }
+
+ public void visit(DeleteAction action) {
+ this.builder.append("DELETE FROM {table}");
+ }
+
+ @Override
+ public void visitFieldName(FilterField field) {
+ if (field == BulkUpdateField.PERMISSION) {
+ this.builder.append("permission");
+ } else if (field == BulkUpdateField.SERVER) {
+ this.builder.append("server");
+ } else if (field == BulkUpdateField.WORLD) {
+ this.builder.append("world");
+ } else {
+ throw new AssertionError(field);
+ }
+ }
+
+}
diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/Action.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/BulkUpdateAction.java
similarity index 80%
rename from common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/Action.java
rename to common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/BulkUpdateAction.java
index 25b9d681c..946ebccdc 100644
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/Action.java
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/BulkUpdateAction.java
@@ -25,13 +25,12 @@
package me.lucko.luckperms.common.bulkupdate.action;
-import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder;
import net.luckperms.api.node.Node;
/**
* Represents an action to be applied to a given node.
*/
-public interface Action {
+public interface BulkUpdateAction {
/**
* Gets the name of this action
@@ -44,17 +43,8 @@ public interface Action {
* Applies this action to the given NodeModel, and returns the result.
*
* @param from the node to base changes from
- * @return the new nodemodel instance, or null if the node should be deleted.
+ * @return the new node instance, or null if the node should be deleted.
*/
Node apply(Node from);
- /**
- * Gets this action in SQL form.
- *
- * Will include a placeholder for the table, as "{table}".
- *
- * @param builder the statement builder
- */
- void appendSql(PreparedStatementBuilder builder);
-
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/DeleteAction.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/DeleteAction.java
index 97319562c..d5c300c25 100644
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/DeleteAction.java
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/DeleteAction.java
@@ -25,10 +25,9 @@
package me.lucko.luckperms.common.bulkupdate.action;
-import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder;
import net.luckperms.api.node.Node;
-public class DeleteAction implements Action {
+public class DeleteAction implements BulkUpdateAction {
public static DeleteAction create() {
return new DeleteAction();
@@ -46,9 +45,4 @@ public class DeleteAction implements Action {
public Node apply(Node from) {
return null; // this action just deletes nodes, so return null
}
-
- @Override
- public void appendSql(PreparedStatementBuilder builder) {
- builder.append("DELETE FROM {table}");
- }
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/UpdateAction.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/UpdateAction.java
index 81639b3f4..89a27f658 100644
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/UpdateAction.java
+++ b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/action/UpdateAction.java
@@ -25,28 +25,27 @@
package me.lucko.luckperms.common.bulkupdate.action;
-import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder;
-import me.lucko.luckperms.common.bulkupdate.query.QueryField;
+import me.lucko.luckperms.common.bulkupdate.BulkUpdateField;
import me.lucko.luckperms.common.node.factory.NodeBuilders;
import net.luckperms.api.context.DefaultContextKeys;
import net.luckperms.api.context.MutableContextSet;
import net.luckperms.api.node.Node;
-public class UpdateAction implements Action {
+public class UpdateAction implements BulkUpdateAction {
- public static UpdateAction of(QueryField field, String value) {
+ public static UpdateAction of(BulkUpdateField field, String value) {
return new UpdateAction(field, value);
}
// the field we're updating
- private final QueryField field;
+ private final BulkUpdateField field;
// the new value of the field
- private final String value;
+ private final String newValue;
- private UpdateAction(QueryField field, String value) {
+ private UpdateAction(BulkUpdateField field, String newValue) {
this.field = field;
- this.value = value;
+ this.newValue = newValue;
}
@Override
@@ -54,11 +53,19 @@ public class UpdateAction implements Action {
return "update";
}
+ public BulkUpdateField getField() {
+ return this.field;
+ }
+
+ public String getNewValue() {
+ return this.newValue;
+ }
+
@Override
public Node apply(Node from) {
switch (this.field) {
case PERMISSION:
- return NodeBuilders.determineMostApplicable(this.value)
+ return NodeBuilders.determineMostApplicable(this.newValue)
.value(from.getValue())
.expiry(from.getExpiry())
.context(from.getContexts())
@@ -66,8 +73,8 @@ public class UpdateAction implements Action {
case SERVER: {
MutableContextSet contexts = from.getContexts().mutableCopy();
contexts.removeAll(DefaultContextKeys.SERVER_KEY);
- if (!this.value.equals("global")) {
- contexts.add(DefaultContextKeys.SERVER_KEY, this.value);
+ if (!this.newValue.equals("global")) {
+ contexts.add(DefaultContextKeys.SERVER_KEY, this.newValue);
}
return from.toBuilder()
@@ -77,8 +84,8 @@ public class UpdateAction implements Action {
case WORLD: {
MutableContextSet contexts = from.getContexts().mutableCopy();
contexts.removeAll(DefaultContextKeys.WORLD_KEY);
- if (!this.value.equals("global")) {
- contexts.add(DefaultContextKeys.WORLD_KEY, this.value);
+ if (!this.newValue.equals("global")) {
+ contexts.add(DefaultContextKeys.WORLD_KEY, this.newValue);
}
return from.toBuilder()
@@ -89,10 +96,4 @@ public class UpdateAction implements Action {
throw new RuntimeException();
}
}
-
- @Override
- public void appendSql(PreparedStatementBuilder builder) {
- builder.append("UPDATE {table} SET " + this.field.getSqlName() + "=");
- builder.variable(this.value);
- }
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/comparison/StandardComparison.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/comparison/StandardComparison.java
deleted file mode 100644
index 3152515e1..000000000
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/comparison/StandardComparison.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.comparison;
-
-import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder;
-
-import java.util.regex.Pattern;
-
-/**
- * An enumeration of standard {@link Comparison}s.
- */
-public enum StandardComparison implements Comparison {
-
- EQUAL("==", "=") {
- @Override
- public CompiledExpression compile(String expression) {
- return expression::equalsIgnoreCase;
- }
- },
-
- NOT_EQUAL("!=", "!=") {
- @Override
- public CompiledExpression compile(String expression) {
- return string -> !expression.equalsIgnoreCase(string);
- }
- },
-
- SIMILAR("~~", "LIKE") {
- @Override
- public CompiledExpression compile(String expression) {
- Pattern pattern = StandardComparison.compilePatternForLikeSyntax(expression);
- return string -> pattern.matcher(string).matches();
- }
- },
-
- NOT_SIMILAR("!~", "NOT LIKE") {
- @Override
- public CompiledExpression compile(String expression) {
- Pattern pattern = StandardComparison.compilePatternForLikeSyntax(expression);
- return string -> !pattern.matcher(string).matches();
- }
- };
-
- public static final String WILDCARD = "%";
- public static final String WILDCARD_ONE = "_";
-
- private final String symbol;
- private final String asSql;
-
- StandardComparison(String symbol, String asSql) {
- this.symbol = symbol;
- this.asSql = asSql;
- }
-
- @Override
- public String getSymbol() {
- return this.symbol;
- }
-
- @Override
- public void appendSql(PreparedStatementBuilder builder) {
- builder.append(this.asSql);
- }
-
- @Override
- public String toString() {
- return this.symbol;
- }
-
- public static StandardComparison parseComparison(String s) {
- for (StandardComparison t : values()) {
- if (t.getSymbol().equals(s)) {
- return t;
- }
- }
- return null;
- }
-
- static Pattern compilePatternForLikeSyntax(String expression) {
- expression = expression.replace(".", "\\.");
-
- // convert from SQL LIKE syntax to regex
- expression = expression.replace(WILDCARD_ONE, ".");
- expression = expression.replace(WILDCARD, ".*");
-
- return Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
- }
-
-}
diff --git a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/query/Query.java b/common/src/main/java/me/lucko/luckperms/common/bulkupdate/query/Query.java
deleted file mode 100644
index 7cf3f6b03..000000000
--- a/common/src/main/java/me/lucko/luckperms/common/bulkupdate/query/Query.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.query;
-
-import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder;
-import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
-import net.luckperms.api.context.DefaultContextKeys;
-import net.luckperms.api.node.Node;
-
-/**
- * Represents a query component
- */
-public class Query {
-
- public static Query of(QueryField field, Constraint constraint) {
- return new Query(field, constraint);
- }
-
- // the field this query is comparing against
- private final QueryField field;
-
- // the constraint
- private final Constraint constraint;
-
- private Query(QueryField field, Constraint constraint) {
- this.field = field;
- this.constraint = constraint;
- }
-
- /**
- * Returns if the given node satisfies this query
- *
- * @param node the node
- * @return true if satisfied
- */
- public boolean isSatisfiedBy(Node node) {
- switch (this.field) {
- case PERMISSION:
- return this.constraint.eval(node.getKey());
- case SERVER:
- return this.constraint.eval(node.getContexts().getAnyValue(DefaultContextKeys.SERVER_KEY).orElse("global"));
- case WORLD:
- return this.constraint.eval(node.getContexts().getAnyValue(DefaultContextKeys.WORLD_KEY).orElse("global"));
- default:
- throw new RuntimeException();
- }
- }
-
- public void appendSql(PreparedStatementBuilder builder) {
- this.constraint.appendSql(builder, this.field.getSqlName());
- }
-
- public QueryField getField() {
- return this.field;
- }
-
- public Constraint getConstraint() {
- return this.constraint;
- }
-}
diff --git a/common/src/main/java/me/lucko/luckperms/common/command/abstraction/ParentCommand.java b/common/src/main/java/me/lucko/luckperms/common/command/abstraction/ParentCommand.java
index d51bb325f..99d8b494f 100644
--- a/common/src/main/java/me/lucko/luckperms/common/command/abstraction/ParentCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/command/abstraction/ParentCommand.java
@@ -86,39 +86,44 @@ public abstract class ParentCommand extends Command {
return;
}
- final String targetArgument = args.get(0);
- I targetId = null;
- if (this.type == Type.TAKES_ARGUMENT_FOR_TARGET) {
- targetId = parseTarget(targetArgument, plugin, sender);
+ if (this.type == Type.TARGETED) {
+ final String targetArgument = args.get(0);
+ I targetId = parseTarget(targetArgument, plugin, sender);
if (targetId == null) {
return;
}
- }
-
- ReentrantLock lock = getLockForTarget(targetId);
- lock.lock();
- try {
- T target = getTarget(targetId, plugin, sender);
- if (target == null) {
- return;
- }
+ ReentrantLock lock = getLockForTarget(targetId);
+ lock.lock();
try {
- sub.execute(plugin, sender, target, args.subList(this.type.minArgs, args.size()), label);
+ T target = getTarget(targetId, plugin, sender);
+ if (target == null) {
+ return;
+ }
+
+ try {
+ sub.execute(plugin, sender, target, args.subList(this.type.minArgs, args.size()), label);
+ } catch (CommandException e) {
+ e.handle(sender, label, sub);
+ }
+
+ cleanup(target, plugin);
+ } finally {
+ lock.unlock();
+ }
+ } else {
+ try {
+ sub.execute(plugin, sender, null, args.subList(this.type.minArgs, args.size()), label);
} catch (CommandException e) {
e.handle(sender, label, sub);
}
-
- cleanup(target, plugin);
- } finally {
- lock.unlock();
}
}
@Override
public List tabComplete(LuckPermsPlugin plugin, Sender sender, ArgumentList args) {
switch (this.type) {
- case TAKES_ARGUMENT_FOR_TARGET:
+ case TARGETED:
return TabCompleter.create()
.at(0, CompletionSupplier.startsWith(() -> getTargets(plugin).stream()))
.at(1, CompletionSupplier.startsWith(() -> getChildren().stream()
@@ -133,7 +138,7 @@ public abstract class ParentCommand extends Command {
.orElse(Collections.emptyList())
)
.complete(args);
- case NO_TARGET_ARGUMENT:
+ case NOT_TARGETED:
return TabCompleter.create()
.at(0, CompletionSupplier.startsWith(() -> getChildren().stream()
.filter(s -> s.isAuthorized(sender))
@@ -178,21 +183,31 @@ public abstract class ParentCommand extends Command {
return getChildren().stream().anyMatch(sc -> sc.isAuthorized(sender));
}
- protected abstract List getTargets(LuckPermsPlugin plugin);
+ protected List getTargets(LuckPermsPlugin plugin) {
+ throw new UnsupportedOperationException();
+ }
- protected abstract I parseTarget(String target, LuckPermsPlugin plugin, Sender sender);
+ protected I parseTarget(String target, LuckPermsPlugin plugin, Sender sender) {
+ throw new UnsupportedOperationException();
+ }
- protected abstract ReentrantLock getLockForTarget(I target);
+ protected ReentrantLock getLockForTarget(I target) {
+ throw new UnsupportedOperationException();
+ }
- protected abstract T getTarget(I target, LuckPermsPlugin plugin, Sender sender);
+ protected T getTarget(I target, LuckPermsPlugin plugin, Sender sender) {
+ throw new UnsupportedOperationException();
+ }
- protected abstract void cleanup(T t, LuckPermsPlugin plugin);
+ protected void cleanup(T t, LuckPermsPlugin plugin) {
+ throw new UnsupportedOperationException();
+ }
public enum Type {
// e.g. /lp log sub-command....
- NO_TARGET_ARGUMENT(0),
+ NOT_TARGETED(0),
// e.g. /lp user sub-command....
- TAKES_ARGUMENT_FOR_TARGET(1);
+ TARGETED(1);
private final int cmdIndex;
private final int minArgs;
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/DeleteGroup.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/DeleteGroup.java
index e3b5a546a..2de521a43 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/group/DeleteGroup.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/DeleteGroup.java
@@ -28,12 +28,9 @@ package me.lucko.luckperms.common.commands.group;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.bulkupdate.BulkUpdateBuilder;
+import me.lucko.luckperms.common.bulkupdate.BulkUpdateField;
import me.lucko.luckperms.common.bulkupdate.DataType;
import me.lucko.luckperms.common.bulkupdate.action.DeleteAction;
-import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
-import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison;
-import me.lucko.luckperms.common.bulkupdate.query.Query;
-import me.lucko.luckperms.common.bulkupdate.query.QueryField;
import me.lucko.luckperms.common.command.abstraction.SingleCommand;
import me.lucko.luckperms.common.command.access.ArgumentPermissions;
import me.lucko.luckperms.common.command.access.CommandPermission;
@@ -43,6 +40,7 @@ import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.config.ConfigKeys;
+import me.lucko.luckperms.common.filter.Comparison;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.messaging.InternalMessagingService;
import me.lucko.luckperms.common.model.Group;
@@ -115,7 +113,7 @@ public class DeleteGroup extends SingleCommand {
.trackStatistics(false)
.dataType(DataType.ALL)
.action(DeleteAction.create())
- .query(Query.of(QueryField.PERMISSION, Constraint.of(StandardComparison.EQUAL, Inheritance.key(groupName))))
+ .filter(BulkUpdateField.PERMISSION, Comparison.EQUAL, Inheritance.key(groupName))
.build();
plugin.getStorage().applyBulkUpdate(operation).whenCompleteAsync((v, ex) -> {
if (ex != null) {
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupParentCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupParentCommand.java
index 356ffb346..507d30395 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupParentCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupParentCommand.java
@@ -60,7 +60,7 @@ public class GroupParentCommand extends ParentCommand {
.build(key -> new ReentrantLock());
public GroupParentCommand() {
- super(CommandSpec.GROUP, "Group", Type.TAKES_ARGUMENT_FOR_TARGET, ImmutableList.>builder()
+ super(CommandSpec.GROUP, "Group", Type.TARGETED, ImmutableList.>builder()
.add(new GroupInfo())
.add(new CommandPermission<>(HolderType.GROUP))
.add(new CommandParent<>(HolderType.GROUP))
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupRename.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupRename.java
index cbef015dc..57cf03349 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupRename.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupRename.java
@@ -28,11 +28,8 @@ package me.lucko.luckperms.common.commands.group;
import me.lucko.luckperms.common.actionlog.LoggedAction;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.bulkupdate.BulkUpdateBuilder;
+import me.lucko.luckperms.common.bulkupdate.BulkUpdateField;
import me.lucko.luckperms.common.bulkupdate.action.UpdateAction;
-import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
-import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison;
-import me.lucko.luckperms.common.bulkupdate.query.Query;
-import me.lucko.luckperms.common.bulkupdate.query.QueryField;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.ArgumentPermissions;
import me.lucko.luckperms.common.command.access.CommandPermission;
@@ -41,6 +38,7 @@ import me.lucko.luckperms.common.command.tabcomplete.CompletionSupplier;
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.command.utils.StorageAssistant;
+import me.lucko.luckperms.common.filter.Comparison;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.node.types.Inheritance;
@@ -112,8 +110,8 @@ public class GroupRename extends ChildCommand {
BulkUpdate operation = BulkUpdateBuilder.create()
.trackStatistics(false)
.dataType(me.lucko.luckperms.common.bulkupdate.DataType.ALL)
- .action(UpdateAction.of(QueryField.PERMISSION, Inheritance.key(newGroupName)))
- .query(Query.of(QueryField.PERMISSION, Constraint.of(StandardComparison.EQUAL, Inheritance.key(target.getName()))))
+ .action(UpdateAction.of(BulkUpdateField.PERMISSION, Inheritance.key(newGroupName)))
+ .filter(BulkUpdateField.PERMISSION, Comparison.EQUAL, Inheritance.key(target.getName()))
.build();
return plugin.getStorage().applyBulkUpdate(operation);
} else {
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 a5a58fa0d..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
@@ -25,25 +25,26 @@
package me.lucko.luckperms.common.commands.log;
-import me.lucko.luckperms.common.actionlog.Log;
+import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
+import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
import me.lucko.luckperms.common.command.utils.ArgumentList;
+import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.misc.DataConstraints;
-import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
import java.util.Locale;
-public class LogGroupHistory extends ChildCommand {
+public class LogGroupHistory extends ChildCommand {
private static final int ENTRIES_PER_PAGE = 10;
public LogGroupHistory() {
@@ -51,44 +52,34 @@ public class LogGroupHistory extends ChildCommand {
}
@Override
- public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
+ public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
String group = args.get(0).toLowerCase(Locale.ROOT);
if (!DataConstraints.GROUP_NAME_TEST.test(group)) {
Message.GROUP_INVALID_ENTRY.send(sender, group);
return;
}
- Paginated content = new Paginated<>(log.getGroupHistory(group));
+ PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 1));
+ LogPage log = plugin.getStorage().getLogPage(ActionFilters.group(group), pageParams).join();
- int page = args.getIntOrDefault(1, Integer.MIN_VALUE);
- if (page != Integer.MIN_VALUE) {
- showLog(page, sender, content);
- } else {
- showLog(content.getMaxPages(ENTRIES_PER_PAGE), sender, content);
- }
- }
+ int page = pageParams.pageNumber();
+ int maxPage = pageParams.getMaxPage(log.getTotalEntries());
- private static void showLog(int page, Sender sender, Paginated log) {
- int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
- if (maxPage == 0) {
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
- if (page == Integer.MIN_VALUE) {
- page = maxPage;
- }
-
if (page < 1 || page > maxPage) {
Message.LOG_INVALID_PAGE_RANGE.send(sender, maxPage);
return;
}
- List> entries = log.getPage(page, ENTRIES_PER_PAGE);
+ List> entries = log.getNumberedContent();
String name = entries.stream().findAny().get().value().getTarget().getName();
Message.LOG_HISTORY_GROUP_HEADER.send(sender, name, page, maxPage);
- for (Paginated.Entry e : entries) {
+ for (LogPage.Entry e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogNotify.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogNotify.java
index 678eb44cb..9361d3535 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogNotify.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogNotify.java
@@ -25,7 +25,6 @@
package me.lucko.luckperms.common.commands.log;
-import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
@@ -43,7 +42,7 @@ import net.luckperms.api.node.Node;
import java.util.Optional;
import java.util.UUID;
-public class LogNotify extends ChildCommand {
+public class LogNotify extends ChildCommand {
private static final String IGNORE_NODE = "luckperms.log.notify.ignoring";
public LogNotify() {
@@ -83,7 +82,7 @@ public class LogNotify extends ChildCommand {
}
@Override
- public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
+ public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
if (sender.isConsole()) {
Message.LOG_NOTIFY_CONSOLE.send(sender);
return;
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogParentCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogParentCommand.java
index 0e368f755..a608ddc3a 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogParentCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogParentCommand.java
@@ -26,22 +26,13 @@
package me.lucko.luckperms.common.commands.log;
import com.google.common.collect.ImmutableList;
-import me.lucko.luckperms.common.actionlog.Log;
import me.lucko.luckperms.common.command.abstraction.Command;
import me.lucko.luckperms.common.command.abstraction.ParentCommand;
import me.lucko.luckperms.common.command.spec.CommandSpec;
-import me.lucko.luckperms.common.locale.Message;
-import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
-import me.lucko.luckperms.common.sender.Sender;
-
-import java.util.List;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class LogParentCommand extends ParentCommand {
- private final ReentrantLock lock = new ReentrantLock();
+public class LogParentCommand extends ParentCommand {
public LogParentCommand() {
- super(CommandSpec.LOG, "Log", Type.NO_TARGET_ARGUMENT, ImmutableList.>builder()
+ super(CommandSpec.LOG, "Log", Type.NOT_TARGETED, ImmutableList.>builder()
.add(new LogRecent())
.add(new LogSearch())
.add(new LogNotify())
@@ -51,38 +42,4 @@ public class LogParentCommand extends ParentCommand {
.build()
);
}
-
- @Override
- protected ReentrantLock getLockForTarget(Void target) {
- return this.lock; // all commands target the same log, so we share a lock between all "targets"
- }
-
- @Override
- protected Log getTarget(Void target, LuckPermsPlugin plugin, Sender sender) {
- Log log = plugin.getStorage().getLog().join();
-
- if (log == null) {
- Message.LOG_LOAD_ERROR.send(sender);
- }
-
- return log;
- }
-
- @Override
- protected void cleanup(Log log, LuckPermsPlugin plugin) {
-
- }
-
- @Override
- protected List getTargets(LuckPermsPlugin plugin) {
- // should never be called if we specify Type.NO_TARGET_ARGUMENT in the constructor
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected Void parseTarget(String target, LuckPermsPlugin plugin, Sender sender) {
- // should never be called if we specify Type.NO_TARGET_ARGUMENT in the constructor
- throw new UnsupportedOperationException();
- }
-
}
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 3e400cd8b..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
@@ -25,22 +25,23 @@
package me.lucko.luckperms.common.commands.log;
-import me.lucko.luckperms.common.actionlog.Log;
+import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
+import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.utils.ArgumentList;
+import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
-import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
import java.util.UUID;
-public class LogRecent extends ChildCommand {
+public class LogRecent extends ChildCommand {
private static final int ENTRIES_PER_PAGE = 10;
public LogRecent() {
@@ -48,39 +49,32 @@ public class LogRecent extends ChildCommand {
}
@Override
- public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
- if (args.isEmpty()) {
- // No page or user
- Paginated content = new Paginated<>(log.getContent());
- showLog(content.getMaxPages(ENTRIES_PER_PAGE), false, sender, content);
- return;
+ public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
+ int page = 1;
+ UUID uuid = null;
+
+ if (!args.isEmpty()) {
+ int pageNo = args.getIntOrDefault(0, Integer.MIN_VALUE);
+ if (pageNo != Integer.MIN_VALUE) {
+ page = pageNo;
+ } else {
+ uuid = args.getUserTarget(0, plugin, sender);
+ if (uuid == null) {
+ return;
+ }
+
+ pageNo = args.getIntOrDefault(1, Integer.MIN_VALUE);
+ if (pageNo != Integer.MIN_VALUE) {
+ page = pageNo;
+ }
+ }
}
- int page = args.getIntOrDefault(0, Integer.MIN_VALUE);
- if (page != Integer.MIN_VALUE) {
- Paginated content = new Paginated<>(log.getContent());
- showLog(page, false, sender, content);
- return;
- }
+ PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, page);
+ LogPage log = plugin.getStorage().getLogPage(uuid == null ? ActionFilters.all() : ActionFilters.source(uuid), pageParams).join();
- // User and possibly page
- UUID uuid = args.getUserTarget(0, plugin, sender);
- if (uuid == null) {
- return;
- }
-
- Paginated content = new Paginated<>(log.getContent(uuid));
- page = args.getIntOrDefault(1, Integer.MIN_VALUE);
- if (page != Integer.MIN_VALUE) {
- showLog(page, true, sender, content);
- } else {
- showLog(content.getMaxPages(ENTRIES_PER_PAGE), true, sender, content);
- }
- }
-
- private static void showLog(int page, boolean specificUser, Sender sender, Paginated log) {
- int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
- if (maxPage == 0) {
+ int maxPage = pageParams.getMaxPage(log.getTotalEntries());
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
@@ -90,8 +84,8 @@ public class LogRecent extends ChildCommand {
return;
}
- List> entries = log.getPage(page, ENTRIES_PER_PAGE);
- if (specificUser) {
+ List> entries = log.getNumberedContent();
+ if (uuid != null) {
String name = entries.stream().findAny().get().value().getSource().getName();
if (name.contains("@")) {
name = name.split("@")[0];
@@ -101,8 +95,9 @@ public class LogRecent extends ChildCommand {
Message.LOG_RECENT_HEADER.send(sender, page, maxPage);
}
- for (Paginated.Entry e : entries) {
+ for (LogPage.Entry e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}
+
}
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 4d82ff01b..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
@@ -25,21 +25,22 @@
package me.lucko.luckperms.common.commands.log;
-import me.lucko.luckperms.common.actionlog.Log;
+import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
+import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.utils.ArgumentList;
+import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
-import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
-public class LogSearch extends ChildCommand {
+public class LogSearch extends ChildCommand {
private static final int ENTRIES_PER_PAGE = 10;
public LogSearch() {
@@ -47,8 +48,8 @@ public class LogSearch extends ChildCommand {
}
@Override
- public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
- int page = Integer.MIN_VALUE;
+ public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
+ int page = 1;
if (args.size() > 1) {
try {
page = Integer.parseInt(args.get(args.size() - 1));
@@ -59,36 +60,26 @@ public class LogSearch extends ChildCommand {
}
final String query = String.join(" ", args);
- Paginated content = new Paginated<>(log.getSearch(query));
+ PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, page);
+ LogPage log = plugin.getStorage().getLogPage(ActionFilters.search(query), pageParams).join();
- if (page != Integer.MIN_VALUE) {
- showLog(page, query, sender, content);
- } else {
- showLog(content.getMaxPages(ENTRIES_PER_PAGE), query, sender, content);
- }
- }
-
- private static void showLog(int page, String query, Sender sender, Paginated log) {
- int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
- if (maxPage == 0) {
+ int maxPage = pageParams.getMaxPage(log.getTotalEntries());
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
- if (page == Integer.MIN_VALUE) {
- page = maxPage;
- }
-
if (page < 1 || page > maxPage) {
Message.LOG_INVALID_PAGE_RANGE.send(sender, maxPage);
return;
}
- List> entries = log.getPage(page, ENTRIES_PER_PAGE);
+ List> entries = log.getNumberedContent();
Message.LOG_SEARCH_HEADER.send(sender, query, page, maxPage);
- for (Paginated.Entry e : entries) {
+ for (LogPage.Entry e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}
+
}
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 0a655a3c1..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
@@ -25,25 +25,26 @@
package me.lucko.luckperms.common.commands.log;
-import me.lucko.luckperms.common.actionlog.Log;
+import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
+import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
import me.lucko.luckperms.common.command.utils.ArgumentList;
+import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
import me.lucko.luckperms.common.storage.misc.DataConstraints;
-import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
import java.util.Locale;
-public class LogTrackHistory extends ChildCommand {
+public class LogTrackHistory extends ChildCommand {
private static final int ENTRIES_PER_PAGE = 10;
public LogTrackHistory() {
@@ -51,44 +52,33 @@ public class LogTrackHistory extends ChildCommand {
}
@Override
- public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
+ public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
String track = args.get(0).toLowerCase(Locale.ROOT);
if (!DataConstraints.TRACK_NAME_TEST.test(track)) {
Message.TRACK_INVALID_ENTRY.send(sender, track);
return;
}
+ PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 1));
+ LogPage log = plugin.getStorage().getLogPage(ActionFilters.track(track), pageParams).join();
- Paginated content = new Paginated<>(log.getTrackHistory(track));
+ int page = pageParams.pageNumber();
+ int maxPage = pageParams.getMaxPage(log.getTotalEntries());
- int page = args.getIntOrDefault(1, Integer.MIN_VALUE);
- if (page != Integer.MIN_VALUE) {
- showLog(page, sender, content);
- } else {
- showLog(content.getMaxPages(ENTRIES_PER_PAGE), sender, content);
- }
- }
-
- private static void showLog(int page, Sender sender, Paginated log) {
- int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
- if (maxPage == 0) {
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
- if (page == Integer.MIN_VALUE) {
- page = maxPage;
- }
-
if (page < 1 || page > maxPage) {
Message.LOG_INVALID_PAGE_RANGE.send(sender, maxPage);
return;
}
- List> entries = log.getPage(page, ENTRIES_PER_PAGE);
+ List> entries = log.getNumberedContent();
String name = entries.stream().findAny().get().value().getTarget().getName();
Message.LOG_HISTORY_TRACK_HEADER.send(sender, name, page, maxPage);
- for (Paginated.Entry e : entries) {
+ for (LogPage.Entry e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}
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 cb04d89e9..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
@@ -25,22 +25,23 @@
package me.lucko.luckperms.common.commands.log;
-import me.lucko.luckperms.common.actionlog.Log;
+import me.lucko.luckperms.common.actionlog.LogPage;
import me.lucko.luckperms.common.actionlog.LoggedAction;
+import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.utils.ArgumentList;
+import me.lucko.luckperms.common.filter.PageParameters;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
-import me.lucko.luckperms.common.util.Paginated;
import me.lucko.luckperms.common.util.Predicates;
import java.util.List;
import java.util.UUID;
-public class LogUserHistory extends ChildCommand {
+public class LogUserHistory extends ChildCommand {
private static final int ENTRIES_PER_PAGE = 10;
public LogUserHistory() {
@@ -48,25 +49,19 @@ public class LogUserHistory extends ChildCommand {
}
@Override
- public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
+ public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
UUID uuid = args.getUserTarget(0, plugin, sender);
if (uuid == null) {
return;
}
- Paginated content = new Paginated<>(log.getUserHistory(uuid));
+ PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 1));
+ LogPage log = plugin.getStorage().getLogPage(ActionFilters.user(uuid), pageParams).join();
- int page = args.getIntOrDefault(1, Integer.MIN_VALUE);
- if (page != Integer.MIN_VALUE) {
- showLog(page, sender, content);
- } else {
- showLog(content.getMaxPages(ENTRIES_PER_PAGE), sender, content);
- }
- }
+ int page = pageParams.pageNumber();
+ int maxPage = pageParams.getMaxPage(log.getTotalEntries());
- private static void showLog(int page, Sender sender, Paginated log) {
- int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
- if (maxPage == 0) {
+ if (log.getTotalEntries() == 0) {
Message.LOG_NO_ENTRIES.send(sender);
return;
}
@@ -76,11 +71,11 @@ public class LogUserHistory extends ChildCommand {
return;
}
- List> entries = log.getPage(page, ENTRIES_PER_PAGE);
+ List> entries = log.getNumberedContent();
String name = entries.stream().findAny().get().value().getTarget().getName();
Message.LOG_HISTORY_USER_HEADER.send(sender, name, page, maxPage);
- for (Paginated.Entry e : entries) {
+ for (LogPage.Entry e : entries) {
Message.LOG_ENTRY.send(sender, e.position(), e.value());
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/BulkUpdateCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/BulkUpdateCommand.java
index d5e9ede5e..b957dc6f7 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/BulkUpdateCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/BulkUpdateCommand.java
@@ -28,15 +28,12 @@ package me.lucko.luckperms.common.commands.misc;
import com.github.benmanes.caffeine.cache.Cache;
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
import me.lucko.luckperms.common.bulkupdate.BulkUpdateBuilder;
+import me.lucko.luckperms.common.bulkupdate.BulkUpdateField;
+import me.lucko.luckperms.common.bulkupdate.BulkUpdateSqlBuilder;
import me.lucko.luckperms.common.bulkupdate.BulkUpdateStatistics;
import me.lucko.luckperms.common.bulkupdate.DataType;
import me.lucko.luckperms.common.bulkupdate.action.DeleteAction;
import me.lucko.luckperms.common.bulkupdate.action.UpdateAction;
-import me.lucko.luckperms.common.bulkupdate.comparison.Comparison;
-import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
-import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison;
-import me.lucko.luckperms.common.bulkupdate.query.Query;
-import me.lucko.luckperms.common.bulkupdate.query.QueryField;
import me.lucko.luckperms.common.command.abstraction.CommandException;
import me.lucko.luckperms.common.command.abstraction.SingleCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
@@ -44,6 +41,7 @@ import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.utils.ArgumentException;
import me.lucko.luckperms.common.command.utils.ArgumentList;
import me.lucko.luckperms.common.config.ConfigKeys;
+import me.lucko.luckperms.common.filter.Comparison;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.sender.Sender;
@@ -112,7 +110,7 @@ public class BulkUpdateCommand extends SingleCommand {
}
String field = args.remove(0);
- QueryField queryField = QueryField.of(field);
+ BulkUpdateField queryField = BulkUpdateField.of(field);
if (queryField == null) {
throw new ArgumentException.DetailedUsage();
}
@@ -131,20 +129,20 @@ public class BulkUpdateCommand extends SingleCommand {
return;
}
- QueryField field = QueryField.of(parts[0]);
+ BulkUpdateField field = BulkUpdateField.of(parts[0]);
if (field == null) {
Message.BULK_UPDATE_INVALID_CONSTRAINT.send(sender, constraint);
return;
}
- Comparison comparison = StandardComparison.parseComparison(parts[1]);
+ Comparison comparison = Comparison.parse(parts[1]);
if (comparison == null) {
Message.BULK_UPDATE_INVALID_COMPARISON.send(sender, parts[1]);
return;
}
String expr = parts[2];
- bulkUpdateBuilder.query(Query.of(field, Constraint.of(comparison, expr)));
+ bulkUpdateBuilder.filter(field, comparison, expr);
}
BulkUpdate bulkUpdate = bulkUpdateBuilder.build();
@@ -155,7 +153,11 @@ public class BulkUpdateCommand extends SingleCommand {
String id = String.format("%04d", ThreadLocalRandom.current().nextInt(10000));
this.pendingOperations.put(id, bulkUpdate);
- Message.BULK_UPDATE_QUEUED.send(sender, bulkUpdate.buildAsSql().toReadableString().replace("{table}", bulkUpdate.getDataType().getName()));
+ BulkUpdateSqlBuilder sqlBuilder = new BulkUpdateSqlBuilder();
+ sqlBuilder.visit(bulkUpdate);
+ String readableSql = sqlBuilder.builder().toReadableString().replace("{table}", bulkUpdate.getDataType().getName());
+
+ Message.BULK_UPDATE_QUEUED.send(sender, readableSql);
Message.BULK_UPDATE_CONFIRM.send(sender, label, id);
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java
index c68f612ac..ee003abf6 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/SearchCommand.java
@@ -26,9 +26,6 @@
package me.lucko.luckperms.common.commands.misc;
import com.google.common.collect.Maps;
-import me.lucko.luckperms.common.bulkupdate.comparison.Comparison;
-import me.lucko.luckperms.common.bulkupdate.comparison.Constraint;
-import me.lucko.luckperms.common.bulkupdate.comparison.StandardComparison;
import me.lucko.luckperms.common.cache.LoadingMap;
import me.lucko.luckperms.common.command.abstraction.SingleCommand;
import me.lucko.luckperms.common.command.access.CommandPermission;
@@ -36,6 +33,7 @@ import me.lucko.luckperms.common.command.spec.CommandSpec;
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
import me.lucko.luckperms.common.command.utils.ArgumentList;
+import me.lucko.luckperms.common.filter.Comparison;
import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.HolderType;
import me.lucko.luckperms.common.node.comparator.NodeEntryComparator;
@@ -62,13 +60,13 @@ public class SearchCommand extends SingleCommand {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, ArgumentList args, String label) {
- Comparison comparison = StandardComparison.parseComparison(args.get(0));
+ Comparison comparison = Comparison.parse(args.get(0));
if (comparison == null) {
- comparison = StandardComparison.EQUAL;
+ comparison = Comparison.EQUAL;
args.add(0, "==");
}
- ConstraintNodeMatcher matcher = StandardNodeMatchers.of(Constraint.of(comparison, args.get(1)));
+ ConstraintNodeMatcher matcher = StandardNodeMatchers.key(args.get(1), comparison);
int page = args.getIntOrDefault(2, 1);
Message.SEARCH_SEARCHING.send(sender, matcher.toString());
@@ -120,7 +118,7 @@ public class SearchCommand extends SingleCommand {
headerMessage.send(sender, page, pages.size(), results.size());
for (Map.Entry> ent : mappedContent) {
- Message.SEARCH_NODE_ENTRY.send(sender, comparison != StandardComparison.EQUAL, ent.getValue().getNode(), ent.getKey(), holderType, label, sender.getPlugin());
+ Message.SEARCH_NODE_ENTRY.send(sender, comparison != Comparison.EQUAL, ent.getValue().getNode(), ent.getKey(), holderType, label, sender.getPlugin());
}
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/TrackParentCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/TrackParentCommand.java
index 659f49ad8..505747ce7 100644
--- a/common/src/main/java/me/lucko/luckperms/common/commands/track/TrackParentCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/TrackParentCommand.java
@@ -53,7 +53,7 @@ public class TrackParentCommand extends ParentCommand