Compare commits
34
Commits
feat/filter
...
v5.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0486bc885b | ||
|
|
27e7551e2b | ||
|
|
b77d5759d3 | ||
|
|
96abc0d4fe | ||
|
|
1a24a6a155 | ||
|
|
95ea491787 | ||
|
|
626d08431e | ||
|
|
94e7e11183 | ||
|
|
f64bf04ba4 | ||
|
|
7744913df2 | ||
|
|
6b7283ac83 | ||
|
|
9bc8a61e2d | ||
|
|
5e24a7068c | ||
|
|
f351369a51 | ||
|
|
1bf0deb5a5 | ||
|
|
5b82837b80 | ||
|
|
0fef481d48 | ||
|
|
f2040ab815 | ||
|
|
b18717edef | ||
|
|
29c93fac4f | ||
|
|
2e67011f45 | ||
|
|
a92e04f605 | ||
|
|
8d65693d9a | ||
|
|
8973abd7f1 | ||
|
|
9420efd3ac | ||
|
|
c773126a0f | ||
|
|
9d80de5d5c | ||
|
|
9bf30fc839 | ||
|
|
136a4859f3 | ||
|
|
642f1d3019 | ||
|
|
b21753f5e9 | ||
|
|
9cc129466b | ||
|
|
55440cac01 | ||
|
|
9e7a3d26e4 |
No files matched your search
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
+14
-16
@@ -19,26 +19,24 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: validate gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@v1
|
||||
|
||||
- uses: actions/setup-java@v3
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
uses: gradle/actions/setup-gradle@v4
|
||||
|
||||
- name: Run build and tests with Gradle wrapper
|
||||
run: ./gradlew test build -PdockerTests
|
||||
|
||||
- name: Publish test report
|
||||
uses: mikepenz/action-junit-report@v3
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
if: success() || failure()
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
@@ -46,7 +44,7 @@ jobs:
|
||||
detailed_summary: true
|
||||
|
||||
- name: Upload all artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: jars
|
||||
path: |
|
||||
@@ -61,7 +59,7 @@ jobs:
|
||||
standalone/loader/build/libs/LuckPerms-Standalone-*.jar
|
||||
|
||||
- name: Upload standalone artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: standalone-binary
|
||||
path: standalone/loader/build/libs/LuckPerms-Standalone-*.jar
|
||||
@@ -76,12 +74,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Retrieve saved standalone jar artifact
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: standalone-binary
|
||||
path: standalone/docker/
|
||||
@@ -90,13 +88,13 @@ jobs:
|
||||
run: mv standalone/docker/LuckPerms-Standalone-*.jar standalone/docker/luckperms-standalone.jar
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -108,7 +106,7 @@ jobs:
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
flavor: |
|
||||
@@ -121,7 +119,7 @@ jobs:
|
||||
type=raw,enable=${{ github.ref == 'refs/heads/master' }},value=${{ env.luckperms_version }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: standalone/docker/
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
+6
-6
@@ -1,5 +1,5 @@
|
||||
group = 'net.luckperms'
|
||||
project.version = '5.4'
|
||||
project.version = '5.5'
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
@@ -8,8 +8,8 @@ jar {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.checkerframework:checker-qual:3.21.2'
|
||||
compileOnly 'org.jetbrains:annotations:23.1.0'
|
||||
compileOnly 'org.checkerframework:checker-qual:3.49.3'
|
||||
compileOnly 'org.jetbrains:annotations:26.0.2'
|
||||
}
|
||||
|
||||
// Only used occasionally for deployment - not needed for normal builds.
|
||||
@@ -24,13 +24,13 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
|
||||
options.charSet = 'UTF-8'
|
||||
options.links(
|
||||
'https://checkerframework.org/api/',
|
||||
'https://javadoc.io/static/org.jetbrains/annotations/23.0.0/'
|
||||
'https://javadoc.io/static/org.jetbrains/annotations/26.0.2/'
|
||||
)
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
options.addStringOption('-since', '5.0,5.1,5.2,5.3,5.4,5.5')
|
||||
|
||||
if (JavaVersion.current() > JavaVersion.VERSION_1_8) {
|
||||
options.links.add('https://docs.oracle.com/en/java/javase/11/docs/api/')
|
||||
options.links.add('https://docs.oracle.com/en/java/javase/21/docs/api/')
|
||||
} else {
|
||||
options.links.add('https://docs.oracle.com/javase/8/docs/api/')
|
||||
}
|
||||
@@ -63,7 +63,7 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
|
||||
|
||||
pom {
|
||||
name = 'LuckPerms API'
|
||||
description = 'A permissions plugin for Minecraft servers.'
|
||||
description = 'A permissions manager for Minecraft servers.'
|
||||
url = 'https://luckperms.net'
|
||||
|
||||
licenses {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<p>
|
||||
LuckPerms is a permissions plugin for Minecraft servers. It allows server admins to control what
|
||||
LuckPerms is a permissions manager for Minecraft servers. It allows server admins to control what
|
||||
features players can use by creating groups and assigning permissions.
|
||||
</p>
|
||||
<h4>Useful Links</h4>
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
@@ -79,7 +79,8 @@ public final class LuckPermsProvider {
|
||||
" a) the LuckPerms plugin is not installed or it failed to enable\n" +
|
||||
" b) the plugin in the stacktrace does not declare a dependency on LuckPerms\n" +
|
||||
" c) the plugin in the stacktrace is retrieving the API before the plugin 'enable' phase\n" +
|
||||
" (call the #get method in onEnable, not the constructor!)\n";
|
||||
" (call the #get method in onEnable, not the constructor!)\n" +
|
||||
" d) the plugin in the stacktrace is incorrectly 'shading' the LuckPerms API into its jar\n";
|
||||
|
||||
NotLoadedException() {
|
||||
super(MESSAGE);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>API users should not implement this interface directly.</p>
|
||||
*/
|
||||
@NonExtendable
|
||||
public interface Action extends Comparable<Action> {
|
||||
|
||||
/**
|
||||
@@ -81,6 +85,7 @@ public interface Action extends Comparable<Action> {
|
||||
/**
|
||||
* Represents the source of an action.
|
||||
*/
|
||||
@NonExtendable
|
||||
interface Source {
|
||||
|
||||
/**
|
||||
@@ -102,6 +107,7 @@ public interface Action extends Comparable<Action> {
|
||||
/**
|
||||
* Represents the target of an action.
|
||||
*/
|
||||
@NonExtendable
|
||||
interface Target {
|
||||
|
||||
/**
|
||||
@@ -126,7 +132,7 @@ public interface Action extends Comparable<Action> {
|
||||
@NonNull Type getType();
|
||||
|
||||
/**
|
||||
* Represents the type of a {@link Target}.
|
||||
* Represents the type of {@link Target}.
|
||||
*/
|
||||
enum Type {
|
||||
USER, GROUP, TRACK
|
||||
|
||||
@@ -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.</p>
|
||||
*
|
||||
* <p>All methods are thread safe, and return immutable and thread safe collections.</p>
|
||||
*
|
||||
* @deprecated Use {@link ActionLogger#queryActions(ActionFilter)} or
|
||||
* {@link ActionLogger#queryActions(ActionFilter, int, int)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ActionLog {
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<ActionLog> getLog();
|
||||
|
||||
/**
|
||||
* Submits a log entry to the plugin to be handled.
|
||||
* Gets all actions from the action log matching the given {@code filter}.
|
||||
*
|
||||
* <p>This method submits the log to the storage provider and broadcasts
|
||||
* it.</p>
|
||||
* <p>If the filter is {@code null}, all actions will be returned.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
* <p>Unlike {@link #queryActions(ActionFilter, int, int)}, this method does not implement any pagination and will return
|
||||
* all entries at once.</p>
|
||||
*
|
||||
* <p>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<List<Action>> queryActions(@NonNull ActionFilter filter);
|
||||
|
||||
/**
|
||||
* Gets a page of actions from the action log matching the given {@code filter}.
|
||||
*
|
||||
* <p>If the filter is {@code null}, all actions will be returned.</p>
|
||||
*
|
||||
* @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<Page<Action>> queryActions(@NonNull ActionFilter filter, int pageSize, int pageNumber);
|
||||
|
||||
/**
|
||||
* Submits a logged action to LuckPerms.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>If you want to submit an action log entry but don't know which method to pick,
|
||||
* use this one.</p>
|
||||
*
|
||||
* @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<Void> 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.
|
||||
*
|
||||
* <p>This method does not broadcast the action or send it through the messaging service.</p>
|
||||
*
|
||||
* @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<Void> 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.
|
||||
*
|
||||
* <p>If enabled, this method will also dispatch the log entry via the
|
||||
* plugins {@link MessagingService}.</p>
|
||||
* <p>The broadcast is made to administrator players on the current instance
|
||||
* and to admins on other connected servers if a messaging service is configured.</p>
|
||||
*
|
||||
* <p>This method does not save the action to the plugin storage backend.</p>
|
||||
*
|
||||
* @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<Void> broadcastAction(@NonNull Action entry);
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package 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.
|
||||
*
|
||||
* <p>API users should not implement this interface directly.</p>
|
||||
*
|
||||
* @since 5.5
|
||||
*/
|
||||
@NonExtendable
|
||||
public interface ActionFilter extends Predicate<Action> {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package 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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@link net.luckperms.api.actionlog.Action} filters.
|
||||
*/
|
||||
package net.luckperms.api.actionlog.filter;
|
||||
@@ -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;
|
||||
|
||||
@@ -63,6 +63,7 @@ public interface DisplayNameNode extends ScopedNode<DisplayNameNode, DisplayName
|
||||
*
|
||||
* @param displayName the display name to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code displayName} is empty
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String displayName) {
|
||||
return builder().displayName(displayName);
|
||||
|
||||
@@ -67,6 +67,7 @@ public interface InheritanceNode extends ScopedNode<InheritanceNode, Inheritance
|
||||
*
|
||||
* @param group the group to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code group} is not a valid group name
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String group) {
|
||||
return builder().group(group);
|
||||
|
||||
@@ -71,6 +71,7 @@ public interface MetaNode extends ScopedNode<MetaNode, MetaNode.Builder> {
|
||||
* @param key the meta key to set
|
||||
* @param value the meta value to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code key} is empty
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String key, @NonNull String value) {
|
||||
return builder().key(key).value(value);
|
||||
|
||||
@@ -88,6 +88,7 @@ public interface PermissionNode extends ScopedNode<PermissionNode, PermissionNod
|
||||
*
|
||||
* @param permission the permission to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code permission} is empty
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String permission) {
|
||||
return builder().permission(permission);
|
||||
|
||||
@@ -75,6 +75,7 @@ public interface RegexPermissionNode extends ScopedNode<RegexPermissionNode, Reg
|
||||
*
|
||||
* @param pattern the pattern to set
|
||||
* @return the builder
|
||||
* @throws IllegalArgumentException if {@code pattern} is empty
|
||||
*/
|
||||
static @NonNull Builder builder(@NonNull String pattern) {
|
||||
return builder().pattern(pattern);
|
||||
|
||||
@@ -76,6 +76,7 @@ public interface Platform {
|
||||
NUKKIT("Nukkit"),
|
||||
VELOCITY("Velocity"),
|
||||
FABRIC("Fabric"),
|
||||
NEOFORGE("NeoForge"),
|
||||
FORGE("Forge"),
|
||||
STANDALONE("Standalone");
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public interface DataTypeFilterFunction {
|
||||
|
||||
/**
|
||||
* Creates a {@link DataTypeFilterFunction} that always returns the given
|
||||
* {@code predicate}.
|
||||
* {@code predicate} (commonly one of the values in {@link DataTypeFilter}).
|
||||
*
|
||||
* @param predicate the predicate
|
||||
* @return the data type filter function
|
||||
|
||||
+24
-13
@@ -23,20 +23,31 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.fabric.event;
|
||||
package net.luckperms.api.util;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
// TODO: Use Fabric API alternative when merged.
|
||||
public interface PlayerChangeWorldCallback {
|
||||
Event<PlayerChangeWorldCallback> EVENT = EventFactory.createArrayBacked(PlayerChangeWorldCallback.class, callbacks -> (originalWorld, destination, player) -> {
|
||||
for (PlayerChangeWorldCallback callback : callbacks) {
|
||||
callback.onChangeWorld(originalWorld, destination, player);
|
||||
}
|
||||
});
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a page of entries.
|
||||
*
|
||||
* @since 5.5
|
||||
*/
|
||||
public interface Page<T> {
|
||||
|
||||
/**
|
||||
* Gets the entries on this page.
|
||||
*
|
||||
* @return the entries
|
||||
*/
|
||||
@NonNull List<T> 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();
|
||||
|
||||
void onChangeWorld(ServerWorld originalWorld, ServerWorld destination, ServerPlayerEntity player);
|
||||
}
|
||||
+2
-2
@@ -13,7 +13,7 @@ subprojects {
|
||||
apply plugin: 'org.cadixdev.licenser'
|
||||
|
||||
group = 'me.lucko.luckperms'
|
||||
version = '5.4-SNAPSHOT'
|
||||
version = '5.5-SNAPSHOT'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
@@ -52,7 +52,7 @@ subprojects {
|
||||
}
|
||||
|
||||
project.ext.majorVersion = '5'
|
||||
project.ext.minorVersion = '4'
|
||||
project.ext.minorVersion = '5'
|
||||
project.ext.patchVersion = determinePatchVersion()
|
||||
project.ext.apiVersion = project.ext.majorVersion + '.' + project.ext.minorVersion
|
||||
project.ext.fullVersion = project.ext.apiVersion + '.' + project.ext.patchVersion
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ dependencies {
|
||||
compileOnly project(':common:loader-utils')
|
||||
|
||||
compileOnly 'com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT'
|
||||
compileOnly('net.kyori:adventure-platform-bukkit:4.3.3') {
|
||||
compileOnly('net.kyori:adventure-platform-bukkit:4.4.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'adventure-nbt')
|
||||
|
||||
@@ -25,85 +25,46 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.context;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.cache.LoadingMap;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.manager.ContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.LuckPermsPermissible;
|
||||
import me.lucko.luckperms.bukkit.inject.permissible.PermissibleInjector;
|
||||
import me.lucko.luckperms.common.context.manager.DetachedContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
|
||||
import net.luckperms.api.query.OptionKey;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BukkitContextManager extends ContextManager<Player, Player> {
|
||||
public class BukkitContextManager extends DetachedContextManager<Player, Player> {
|
||||
|
||||
public static final OptionKey<Boolean> OP_OPTION = OptionKey.of("op", Boolean.class);
|
||||
|
||||
// cache the creation of ContextsCache instances for online players with no expiry
|
||||
private final LoadingMap<Player, QueryOptionsCache<Player>> onlineSubjectCaches = LoadingMap.of(key -> new QueryOptionsCache<>(key, this));
|
||||
|
||||
// cache the creation of ContextsCache instances for offline players with a 1m expiry
|
||||
private final LoadingCache<Player, QueryOptionsCache<Player>> offlineSubjectCaches = CaffeineFactory.newBuilder()
|
||||
.expireAfterAccess(1, TimeUnit.MINUTES)
|
||||
.build(key -> {
|
||||
QueryOptionsCache<Player> cache = this.onlineSubjectCaches.getIfPresent(key);
|
||||
if (cache != null) {
|
||||
return cache;
|
||||
}
|
||||
return new QueryOptionsCache<>(key, this);
|
||||
});
|
||||
|
||||
public BukkitContextManager(LPBukkitPlugin plugin) {
|
||||
super(plugin, Player.class, Player.class);
|
||||
}
|
||||
|
||||
public void onPlayerQuit(Player player) {
|
||||
this.onlineSubjectCaches.remove(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId(Player player) {
|
||||
return player.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptionsCache<Player> getCacheFor(Player subject) {
|
||||
if (subject == null) {
|
||||
throw new NullPointerException("subject");
|
||||
}
|
||||
|
||||
if (subject.isOnline()) {
|
||||
return this.onlineSubjectCaches.get(subject);
|
||||
} else {
|
||||
return this.offlineSubjectCaches.get(subject);
|
||||
public @Nullable QueryOptionsSupplier getQueryOptionsSupplier(Player subject) {
|
||||
Objects.requireNonNull(subject, "subject");
|
||||
LuckPermsPermissible permissible = PermissibleInjector.get(subject);
|
||||
if (permissible != null) {
|
||||
return permissible.getQueryOptionsSupplier();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invalidateCache(Player subject) {
|
||||
QueryOptionsCache<Player> cache = this.onlineSubjectCaches.getIfPresent(subject);
|
||||
if (cache != null) {
|
||||
cache.invalidate();
|
||||
}
|
||||
|
||||
cache = this.offlineSubjectCaches.getIfPresent(subject);
|
||||
if (cache != null) {
|
||||
cache.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions formQueryOptions(Player subject, ImmutableContextSet contextSet) {
|
||||
QueryOptions.Builder queryOptions = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder();
|
||||
public void customizeQueryOptions(Player subject, QueryOptions.Builder builder) {
|
||||
if (subject.isOp()) {
|
||||
queryOptions.option(OP_OPTION, true);
|
||||
builder.option(OP_OPTION, true);
|
||||
}
|
||||
|
||||
return queryOptions.context(contextSet).build();
|
||||
}
|
||||
}
|
||||
+11
-9
@@ -32,7 +32,7 @@ import me.lucko.luckperms.bukkit.calculator.OpProcessor;
|
||||
import me.lucko.luckperms.bukkit.calculator.PermissionMapProcessor;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
@@ -68,7 +68,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* "Hot" method calls, (namely #hasPermission) are significantly faster than the base implementation.
|
||||
*
|
||||
* This class is **thread safe**. This means that when LuckPerms is installed on the server,
|
||||
* is is safe to call Player#hasPermission asynchronously.
|
||||
* it is safe to call Player#hasPermission asynchronously.
|
||||
*/
|
||||
public class LuckPermsPermissible extends PermissibleBase {
|
||||
|
||||
@@ -93,7 +93,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
// caches context lookups for the player
|
||||
private final QueryOptionsCache<Player> queryOptionsSupplier;
|
||||
private final QueryOptionsSupplier queryOptionsSupplier;
|
||||
|
||||
// the players previous permissible. (the one they had before this one was injected)
|
||||
private PermissibleBase oldPermissible = null;
|
||||
@@ -110,7 +110,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
this.user = Objects.requireNonNull(user, "user");
|
||||
this.player = Objects.requireNonNull(player, "player");
|
||||
this.plugin = Objects.requireNonNull(plugin, "plugin");
|
||||
this.queryOptionsSupplier = plugin.getContextManager().getCacheFor(player);
|
||||
this.queryOptionsSupplier = plugin.getContextManager().createQueryOptionsSupplier(player);
|
||||
|
||||
injectFakeAttachmentsList();
|
||||
}
|
||||
@@ -293,7 +293,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
// the query options cache when op status changes.
|
||||
// (#invalidate is a fast call)
|
||||
if (this.queryOptionsSupplier != null) { // this method is called by the super class constructor, before this class has fully initialised
|
||||
this.queryOptionsSupplier.invalidate();
|
||||
this.queryOptionsSupplier.invalidateCache();
|
||||
}
|
||||
|
||||
// but we don't need to do anything else in this method, unlike the CB impl.
|
||||
@@ -316,6 +316,10 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
public QueryOptionsSupplier getQueryOptionsSupplier() {
|
||||
return this.queryOptionsSupplier;
|
||||
}
|
||||
|
||||
PermissibleBase getOldPermissible() {
|
||||
return this.oldPermissible;
|
||||
}
|
||||
@@ -409,9 +413,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
@Override public PermissionAttachment remove(int index) { throw new UnsupportedOperationException(); }
|
||||
@Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
|
||||
@Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
|
||||
@Override
|
||||
public @NonNull ListIterator<PermissionAttachment> listIterator(int index) { throw new UnsupportedOperationException(); }
|
||||
@Override
|
||||
public @NonNull List<PermissionAttachment> subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); }
|
||||
@Override public @NonNull ListIterator<PermissionAttachment> listIterator(int index) { throw new UnsupportedOperationException(); }
|
||||
@Override public @NonNull List<PermissionAttachment> subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); }
|
||||
}
|
||||
}
|
||||
+14
@@ -30,6 +30,7 @@ import me.lucko.luckperms.common.plugin.logging.PluginLogger;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
@@ -161,6 +162,19 @@ public final class PermissibleInjector {
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable LuckPermsPermissible get(Player player) {
|
||||
PermissibleBase permissibleBase;
|
||||
try {
|
||||
permissibleBase = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
|
||||
} catch (IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
if (permissibleBase instanceof LuckPermsPermissible) {
|
||||
return (LuckPermsPermissible) permissibleBase;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void checkInjected(Player player, PluginLogger logger) {
|
||||
PermissibleBase permissibleBase;
|
||||
try {
|
||||
|
||||
@@ -253,9 +253,6 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
if (this.plugin.getConfiguration().get(ConfigKeys.AUTO_OP)) {
|
||||
player.setOp(false);
|
||||
}
|
||||
|
||||
// remove their contexts cache
|
||||
this.plugin.getContextManager().onPlayerQuit(player);
|
||||
}, 1L);
|
||||
}
|
||||
|
||||
|
||||
+19
-2
@@ -36,13 +36,26 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.event.server.RemoteServerCommandEvent;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BukkitPlatformListener implements Listener {
|
||||
private static final Pattern OP_COMMAND_PATTERN = Pattern.compile("^/?(\\w+:)?(deop|op)( .*)?$", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final boolean PLUGIN_DESCRIPTION_FILE_PROVIDES_SUPPORTED;
|
||||
|
||||
static {
|
||||
boolean supported = false;
|
||||
try {
|
||||
PluginDescriptionFile.class.getMethod("getProvides");
|
||||
supported = true;
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
PLUGIN_DESCRIPTION_FILE_PROVIDES_SUPPORTED = supported;
|
||||
}
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
|
||||
public BukkitPlatformListener(LPBukkitPlugin plugin) {
|
||||
@@ -81,7 +94,11 @@ public class BukkitPlatformListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onPluginEnable(PluginEnableEvent e) {
|
||||
if (e.getPlugin().getName().equalsIgnoreCase("Vault")) {
|
||||
Plugin p = e.getPlugin();
|
||||
boolean shouldHook = p.getName().equalsIgnoreCase("Vault") ||
|
||||
(PLUGIN_DESCRIPTION_FILE_PROVIDES_SUPPORTED && p.getDescription().getProvides().contains("Vault"));
|
||||
|
||||
if (shouldHook) {
|
||||
this.plugin.tryVaultHook(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,3 +719,33 @@ register-command-list-data: true
|
||||
# If LuckPerms should attempt to resolve Vanilla command target selectors for LP commands.
|
||||
# See here for more info: https://minecraft.wiki/w/Target_selectors
|
||||
resolve-command-selectors: false
|
||||
|
||||
# If the plugin should run in "read-only" mode for commands.
|
||||
#
|
||||
# In this mode, players or the console will only be able to execute commands that read or view
|
||||
# data, and will not be able to execute any LP commands that modify data.
|
||||
#
|
||||
# If enabling read-only mode for just players, be aware that some other plugins may allow players
|
||||
# to execute commands as the console, allowing them to run LP commands indirectly.
|
||||
#
|
||||
# Note: This does not affect interactions with LuckPerms via the API.
|
||||
commands-read-only-mode:
|
||||
players: false
|
||||
console: false
|
||||
|
||||
# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being
|
||||
# executed. In a sense this is a more extreme version of read-only mode (see above).
|
||||
#
|
||||
# LuckPerms will still act as the permission manager, but server administrators will be unable to
|
||||
# make changes via commands.
|
||||
#
|
||||
# If disabling commands just for players, be aware that some other plugins may allow players to
|
||||
# execute commands as the console, allowing them to run commands indirectly.
|
||||
#
|
||||
# If commands are disabled for both players and the console, LuckPerms will not attempt to register
|
||||
# a command with the server at all & in a sense will be invisible to both players and admins.
|
||||
#
|
||||
# Note: This does not affect interactions with LuckPerms via the API.
|
||||
disable-luckperms-commands:
|
||||
players: false
|
||||
console: false
|
||||
+1
-1
@@ -7,7 +7,7 @@ dependencies {
|
||||
compileOnly project(':common:loader-utils')
|
||||
|
||||
compileOnly 'net.md-5:bungeecord-api:1.16-R0.4'
|
||||
compileOnly('net.kyori:adventure-platform-bungeecord:4.3.3') {
|
||||
compileOnly('net.kyori:adventure-platform-bungeecord:4.4.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'adventure-nbt')
|
||||
|
||||
@@ -25,25 +25,13 @@
|
||||
|
||||
package me.lucko.luckperms.bungee.context;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.context.manager.ContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.InlineQueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import me.lucko.luckperms.common.context.manager.SimpleContextManager;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BungeeContextManager extends ContextManager<ProxiedPlayer, ProxiedPlayer> {
|
||||
|
||||
private final LoadingCache<ProxiedPlayer, QueryOptions> contextsCache = CaffeineFactory.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(this::calculate);
|
||||
|
||||
public class BungeeContextManager extends SimpleContextManager<ProxiedPlayer, ProxiedPlayer> {
|
||||
public BungeeContextManager(LPBungeePlugin plugin) {
|
||||
super(plugin, ProxiedPlayer.class, ProxiedPlayer.class);
|
||||
}
|
||||
@@ -52,35 +40,4 @@ public class BungeeContextManager extends ContextManager<ProxiedPlayer, ProxiedP
|
||||
public UUID getUniqueId(ProxiedPlayer player) {
|
||||
return player.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptionsSupplier getCacheFor(ProxiedPlayer subject) {
|
||||
if (subject == null) {
|
||||
throw new NullPointerException("subject");
|
||||
}
|
||||
|
||||
return new InlineQueryOptionsSupplier<>(subject, this.contextsCache);
|
||||
}
|
||||
|
||||
// override getContext, getQueryOptions and invalidateCache to skip the QueryOptionsSupplier
|
||||
@Override
|
||||
public ImmutableContextSet getContext(ProxiedPlayer subject) {
|
||||
return getQueryOptions(subject).context();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions(ProxiedPlayer subject) {
|
||||
return this.contextsCache.get(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invalidateCache(ProxiedPlayer subject) {
|
||||
this.contextsCache.invalidate(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions formQueryOptions(ProxiedPlayer subject, ImmutableContextSet contextSet) {
|
||||
return formQueryOptions(contextSet);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -611,3 +611,33 @@ disable-bulkupdate: false
|
||||
#
|
||||
# - When this happens, the plugin will set their primary group back to default.
|
||||
prevent-primary-group-removal: false
|
||||
|
||||
# If the plugin should run in "read-only" mode for commands.
|
||||
#
|
||||
# In this mode, players or the console will only be able to execute commands that read or view
|
||||
# data, and will not be able to execute any LP commands that modify data.
|
||||
#
|
||||
# If enabling read-only mode for just players, be aware that some other plugins may allow players
|
||||
# to execute commands as the console, allowing them to run LP commands indirectly.
|
||||
#
|
||||
# Note: This does not affect interactions with LuckPerms via the API.
|
||||
commands-read-only-mode:
|
||||
players: false
|
||||
console: false
|
||||
|
||||
# If LuckPerms commands should be disabled. When true, this will prevent all LP commands from being
|
||||
# executed. In a sense this is a more extreme version of read-only mode (see above).
|
||||
#
|
||||
# LuckPerms will still act as the permission manager, but server administrators will be unable to
|
||||
# make changes via commands.
|
||||
#
|
||||
# If disabling commands just for players, be aware that some other plugins may allow players to
|
||||
# execute commands as the console, allowing them to run commands indirectly.
|
||||
#
|
||||
# If commands are disabled for both players and the console, LuckPerms will not attempt to register
|
||||
# a command with the server at all & in a sense will be invisible to both players and admins.
|
||||
#
|
||||
# Note: This does not affect interactions with LuckPerms via the API.
|
||||
disable-luckperms-commands:
|
||||
players: false
|
||||
console: false
|
||||
+18
-6
@@ -4,7 +4,11 @@ plugins {
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform {}
|
||||
useJUnitPlatform {
|
||||
if (!project.hasProperty('dockerTests')) {
|
||||
excludeTags 'docker'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jacocoTestReport {
|
||||
@@ -12,12 +16,19 @@ jacocoTestReport {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'org.slf4j:slf4j-simple:1.7.36'
|
||||
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.20.4'
|
||||
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'
|
||||
testImplementation 'net.luckperms:rest-api-java-client:0.1-SNAPSHOT'
|
||||
|
||||
api project(':api')
|
||||
api 'org.checkerframework:checker-qual:3.12.0'
|
||||
@@ -28,29 +39,29 @@ dependencies {
|
||||
compileOnly 'org.slf4j:slf4j-api:1.7.30'
|
||||
compileOnly 'org.apache.logging.log4j:log4j-api:2.14.0'
|
||||
|
||||
api('net.kyori:adventure-api:4.11.0') {
|
||||
api('net.kyori:adventure-api:4.21.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'checker-qual')
|
||||
exclude(module: 'annotations')
|
||||
}
|
||||
|
||||
api('net.kyori:adventure-text-serializer-gson:4.11.0') {
|
||||
api('net.kyori:adventure-text-serializer-gson:4.21.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'gson')
|
||||
}
|
||||
|
||||
api('net.kyori:adventure-text-serializer-legacy:4.11.0') {
|
||||
api('net.kyori:adventure-text-serializer-legacy:4.21.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
|
||||
api('net.kyori:adventure-text-serializer-plain:4.11.0') {
|
||||
api('net.kyori:adventure-text-serializer-plain:4.21.0') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
|
||||
api("net.kyori:adventure-text-minimessage:4.11.0") {
|
||||
api("net.kyori:adventure-text-minimessage:4.21.0") {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
@@ -90,4 +101,5 @@ dependencies {
|
||||
compileOnly 'org.mongodb:mongodb-driver-legacy:4.5.0'
|
||||
compileOnly 'org.postgresql:postgresql:42.6.0'
|
||||
compileOnly 'org.yaml:snakeyaml:1.28'
|
||||
compileOnly 'net.luckperms:rest-api-java-client:0.1-SNAPSHOT'
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import me.lucko.luckperms.common.util.ImmutableCollectors;
|
||||
import net.luckperms.api.actionlog.Action;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Log {
|
||||
private static final Log EMPTY = new Log(ImmutableList.of());
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static Log empty() {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
private final SortedSet<LoggedAction> content;
|
||||
|
||||
Log(List<LoggedAction> content) {
|
||||
this.content = ImmutableSortedSet.copyOf(content);
|
||||
}
|
||||
|
||||
public SortedSet<LoggedAction> getContent() {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
public SortedSet<LoggedAction> getContent(UUID actor) {
|
||||
return this.content.stream()
|
||||
.filter(e -> e.getSource().getUniqueId().equals(actor))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
|
||||
public SortedSet<LoggedAction> getUserHistory(UUID uniqueId) {
|
||||
return this.content.stream()
|
||||
.filter(e -> e.getTarget().getType() == Action.Target.Type.USER)
|
||||
.filter(e -> e.getTarget().getUniqueId().isPresent() && e.getTarget().getUniqueId().get().equals(uniqueId))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
|
||||
public SortedSet<LoggedAction> getGroupHistory(String name) {
|
||||
return this.content.stream()
|
||||
.filter(e -> e.getTarget().getType() == Action.Target.Type.GROUP)
|
||||
.filter(e -> e.getTarget().getName().equals(name))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
|
||||
public SortedSet<LoggedAction> getTrackHistory(String name) {
|
||||
return this.content.stream()
|
||||
.filter(e -> e.getTarget().getType() == Action.Target.Type.TRACK)
|
||||
.filter(e -> e.getTarget().getName().equals(name))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
|
||||
public SortedSet<LoggedAction> getSearch(String query) {
|
||||
return this.content.stream()
|
||||
.filter(e -> e.matchesSearch(query))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final List<LoggedAction> content = new ArrayList<>();
|
||||
|
||||
public Builder add(LoggedAction e) {
|
||||
this.content.add(e);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Log build() {
|
||||
if (this.content.isEmpty()) {
|
||||
return EMPTY;
|
||||
}
|
||||
return new Log(this.content);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Void> 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<Void> 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<Void> dispatch(LoggedAction entry, Sender sender, LogBroadcastEvent.Origin broadcastOrigin, LogNotifyEvent.Origin origin) {
|
||||
CompletableFuture<Void> storageFuture = logToStorage(entry);
|
||||
CompletableFuture<Void> messagingFuture = logToMessaging(entry);
|
||||
broadcast(entry, broadcastOrigin, origin, sender);
|
||||
return CompletableFuture.allOf(storageFuture, messagingFuture);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> dispatch(LoggedAction entry, Sender sender) {
|
||||
return dispatch(entry, sender, LogBroadcastEvent.Origin.LOCAL, LogNotifyEvent.Origin.LOCAL);
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> 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);
|
||||
}
|
||||
}
|
||||
+30
-34
@@ -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 <T> the element type
|
||||
*/
|
||||
public class Paginated<T> {
|
||||
private final List<T> content;
|
||||
|
||||
public Paginated(Collection<T> content) {
|
||||
this.content = ImmutableList.copyOf(content);
|
||||
public class LogPage {
|
||||
public static LogPage of(List<LoggedAction> content, @Nullable PageParameters params, int totalEntries) {
|
||||
return new LogPage(content, params, totalEntries);
|
||||
}
|
||||
|
||||
public List<T> getContent() {
|
||||
private final List<LoggedAction> content;
|
||||
private final @Nullable PageParameters params;
|
||||
private final int totalEntries;
|
||||
|
||||
LogPage(List<LoggedAction> content, @Nullable PageParameters params, int totalEntries) {
|
||||
this.content = ImmutableList.copyOf(content);
|
||||
this.params = params;
|
||||
this.totalEntries = totalEntries;
|
||||
}
|
||||
|
||||
public List<LoggedAction> getContent() {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
public int getMaxPages(int entriesPerPage) {
|
||||
return (int) Math.ceil((double) this.content.size() / (double) entriesPerPage);
|
||||
public List<Entry<LoggedAction>> getNumberedContent() {
|
||||
int startIndex = this.params != null
|
||||
? this.params.pageSize() * (this.params.pageNumber() - 1)
|
||||
: 0;
|
||||
|
||||
List<Entry<LoggedAction>> numberedContent = new ArrayList<>();
|
||||
for (int i = 0; i < this.content.size(); i++) {
|
||||
int index = startIndex + i + 1;
|
||||
numberedContent.add(new Entry<>(index, this.content.get(i)));
|
||||
}
|
||||
return numberedContent;
|
||||
}
|
||||
|
||||
public List<Entry<T>> getPage(int pageNo, int pageSize) {
|
||||
if (pageNo < 1) {
|
||||
throw new IllegalArgumentException("pageNo cannot be less than 1: " + pageNo);
|
||||
}
|
||||
|
||||
int first = (pageNo - 1) * pageSize;
|
||||
if (this.content.size() <= first) {
|
||||
throw new IllegalStateException("Content does not contain that many elements. (requested page: " + pageNo +
|
||||
", page size: " + pageSize + ", page first index: " + first + ", content size: " + this.content.size() + ")");
|
||||
}
|
||||
|
||||
int last = first + pageSize - 1;
|
||||
List<Entry<T>> out = new ArrayList<>(pageSize);
|
||||
|
||||
for (int i = first; i <= last && i < this.content.size(); i++) {
|
||||
out.add(new Entry<>(i + 1, this.content.get(i)));
|
||||
}
|
||||
|
||||
return out;
|
||||
public int getTotalEntries() {
|
||||
return this.totalEntries;
|
||||
}
|
||||
|
||||
public static final class Entry<T> {
|
||||
@@ -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<Void> 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();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog.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<Action, UUID> SOURCE_UNIQUE_ID = FilterField.named(
|
||||
"SOURCE_UNIQUE_ID",
|
||||
action -> action.getSource().getUniqueId()
|
||||
);
|
||||
public static final FilterField<Action, String> SOURCE_NAME = FilterField.named(
|
||||
"SOURCE_NAME",
|
||||
action -> action.getSource().getName()
|
||||
);
|
||||
public static final FilterField<Action, Action.Target.Type> TARGET_TYPE = FilterField.named(
|
||||
"TARGET_TYPE",
|
||||
action -> action.getTarget().getType()
|
||||
);
|
||||
public static final FilterField<Action, UUID> TARGET_UNIQUE_ID = FilterField.named(
|
||||
"TARGET_UNIQUE_ID",
|
||||
action -> action.getTarget().getUniqueId().orElse(null)
|
||||
);
|
||||
public static final FilterField<Action, String> TARGET_NAME = FilterField.named(
|
||||
"TARGET_NAME",
|
||||
action -> action.getTarget().getName()
|
||||
);
|
||||
public static final FilterField<Action, String> DESCRIPTION = FilterField.named(
|
||||
"DESCRIPTION",
|
||||
action -> action.getDescription()
|
||||
);
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog.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<Action> {
|
||||
public static final ActionFilterMongoBuilder INSTANCE = new ActionFilterMongoBuilder();
|
||||
|
||||
private ActionFilterMongoBuilder() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(FilterField<Action, ?> 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog.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<Action> {
|
||||
|
||||
@Override
|
||||
public void visitFieldName(FilterField<Action, ?> 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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.actionlog.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<Action> all() {
|
||||
return FilterList.empty();
|
||||
}
|
||||
|
||||
// all actions performed by a given source (actor)
|
||||
public static FilterList<Action> source(UUID uniqueId) {
|
||||
return FilterList.and(
|
||||
ActionFields.SOURCE_UNIQUE_ID.isEqualTo(uniqueId, ConstraintFactory.UUIDS)
|
||||
);
|
||||
}
|
||||
|
||||
// all actions affecting a given user
|
||||
public static FilterList<Action> 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<Action> 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<Action> 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<Action> 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> TARGET_TYPE_CONSTRAINT_FACTORY = new ConstraintFactory<Target.Type>() {
|
||||
@Override
|
||||
public Predicate<Target.Type> equal(Target.Type value) {
|
||||
return value::equals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<Target.Type> notEqual(Target.Type value) {
|
||||
return string -> !value.equals(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<Target.Type> similar(Target.Type value) {
|
||||
Pattern pattern = Comparison.compilePatternForLikeSyntax(value.toString());
|
||||
return type -> pattern.matcher(type.toString()).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<Target.Type> notSimilar(Target.Type value) {
|
||||
Pattern pattern = Comparison.compilePatternForLikeSyntax(value.toString());
|
||||
return type -> !pattern.matcher(type.toString()).matches();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.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<Action> filter;
|
||||
|
||||
public ApiActionFilter(FilterList<Action> filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Action action) {
|
||||
return this.filter.evaluate(action);
|
||||
}
|
||||
|
||||
public FilterList<Action> getFilter() {
|
||||
return this.filter;
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.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));
|
||||
}
|
||||
|
||||
}
|
||||
+24
-11
@@ -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<Action> content;
|
||||
|
||||
public ApiActionLog(Log handle) {
|
||||
this.handle = handle;
|
||||
public ApiActionLog(List<LoggedAction> content) {
|
||||
this.content = ImmutableSortedSet.copyOf(content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedSet<Action> getContent() {
|
||||
return (SortedSet) this.handle.getContent();
|
||||
return this.content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedSet<Action> getContent(@NonNull UUID actor) {
|
||||
Objects.requireNonNull(actor, "actor");
|
||||
return (SortedSet) this.handle.getContent(actor);
|
||||
return this.content.stream()
|
||||
.filter(e -> e.getSource().getUniqueId().equals(actor))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedSet<Action> getUserHistory(@NonNull UUID uniqueId) {
|
||||
Objects.requireNonNull(uniqueId, "uuid");
|
||||
return (SortedSet) this.handle.getUserHistory(uniqueId);
|
||||
return this.content.stream()
|
||||
.filter(e -> e.getTarget().getType() == Action.Target.Type.USER)
|
||||
.filter(e -> e.getTarget().getUniqueId().isPresent() && e.getTarget().getUniqueId().get().equals(uniqueId))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedSet<Action> getGroupHistory(@NonNull String name) {
|
||||
Objects.requireNonNull(name, "name");
|
||||
return (SortedSet) this.handle.getGroupHistory(ApiUtils.checkName(name));
|
||||
return this.content.stream()
|
||||
.filter(e -> e.getTarget().getType() == Action.Target.Type.GROUP)
|
||||
.filter(e -> e.getTarget().getName().equals(name))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedSet<Action> getTrackHistory(@NonNull String name) {
|
||||
Objects.requireNonNull(name, "name");
|
||||
return (SortedSet) this.handle.getTrackHistory(ApiUtils.checkName(name));
|
||||
return this.content.stream()
|
||||
.filter(e -> e.getTarget().getType() == Action.Target.Type.TRACK)
|
||||
.filter(e -> e.getTarget().getName().equals(name))
|
||||
.collect(ImmutableCollectors.toSortedSet());
|
||||
}
|
||||
}
|
||||
+57
-4
@@ -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<ActionLog> getLog() {
|
||||
return this.plugin.getStorage().getLog().thenApply(ApiActionLog::new);
|
||||
return this.plugin.getStorage().getLogPage(ActionFilters.all(), null)
|
||||
.thenApply(result -> new ApiActionLog(result.getContent()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CompletableFuture<List<Action>> queryActions(@NonNull ActionFilter filter) {
|
||||
return this.plugin.getStorage().getLogPage(getFilterList(filter), null).thenApply(ActionPage::new).thenApply(Page::entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CompletableFuture<Page<Action>> 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<Void> 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<Void> submitToStorage(@NonNull Action entry) {
|
||||
return this.plugin.getStorage().logAction(entry);
|
||||
return this.plugin.getLogDispatcher().logToStorage((LoggedAction) entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CompletableFuture<Void> broadcastAction(@NonNull Action entry) {
|
||||
return CompletableFuture.runAsync(() -> this.plugin.getLogDispatcher().broadcastFromApi((LoggedAction) entry), this.plugin.getBootstrap().getScheduler().async());
|
||||
LogDispatcher dispatcher = this.plugin.getLogDispatcher();
|
||||
|
||||
CompletableFuture<Void> messagingFuture = dispatcher.logToStorage(((LoggedAction) entry));
|
||||
dispatcher.broadcastFromApi(((LoggedAction) entry));
|
||||
return messagingFuture;
|
||||
}
|
||||
|
||||
private static FilterList<Action> 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<Action> {
|
||||
private final LogPage page;
|
||||
|
||||
private ActionPage(LogPage page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public @NonNull List<Action> entries() {
|
||||
return (List) this.page.getContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int overallSize() {
|
||||
return this.page.getTotalEntries();
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -26,8 +26,8 @@
|
||||
package me.lucko.luckperms.common.api.implementation;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.metastacking.StandardStackElements;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.StandardStackElements;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import net.luckperms.api.metastacking.DuplicateRemovalFunction;
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
|
||||
@@ -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<Query> queries;
|
||||
// a set of filters which data must match to be acted upon
|
||||
private final FilterList<Node> 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<Query> queries, boolean trackStatistics) {
|
||||
public BulkUpdate(DataType dataType, BulkUpdateAction action, FilterList<Node> 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<Query> getQueries() {
|
||||
return this.queries;
|
||||
public FilterList<Node> 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() + ")";
|
||||
}
|
||||
}
|
||||
@@ -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<Query> queries = new LinkedHashSet<>();
|
||||
// a set of filters which data must match to be acted upon
|
||||
private final Set<Filter<Node, String>> 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<Node> 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 + ")";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.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<Node, String> {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.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<Node> {
|
||||
|
||||
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<Node, ?> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-12
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
+20
-19
@@ -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);
|
||||
}
|
||||
}
|
||||
-112
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.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;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -193,7 +193,7 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
}
|
||||
|
||||
public void cleanup() {
|
||||
this.cache.values().removeIf(value -> ((UsageTracked) value).usedSince(TimeUnit.MINUTES.toMillis(2)));
|
||||
this.cache.values().removeIf(value -> !((UsageTracked) value).usedInTheLast(2, TimeUnit.MINUTES));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,14 +25,20 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class UsageTracked {
|
||||
private long lastUsed = System.currentTimeMillis();
|
||||
|
||||
@VisibleForTesting
|
||||
protected long lastUsed = System.currentTimeMillis();
|
||||
|
||||
public void recordUsage() {
|
||||
this.lastUsed = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public boolean usedSince(long duration) {
|
||||
return this.lastUsed > System.currentTimeMillis() - duration;
|
||||
public boolean usedInTheLast(long duration, TimeUnit unit) {
|
||||
return this.lastUsed > System.currentTimeMillis() - unit.toMillis(duration);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
package me.lucko.luckperms.common.cacheddata.metastack;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
package me.lucko.luckperms.common.cacheddata.metastack;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.luckperms.api.metastacking.DuplicateRemovalFunction;
|
||||
+10
-4
@@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
package me.lucko.luckperms.common.cacheddata.metastack;
|
||||
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
@@ -220,8 +220,11 @@ public final class StandardStackElements {
|
||||
@Override
|
||||
public boolean shouldAccumulate(@NonNull ChatMetaType type, @NonNull ChatMetaNode<?, ?> node, @Nullable ChatMetaNode<?, ?> current) {
|
||||
Track track = this.plugin.getTrackManager().getIfLoaded(this.trackName);
|
||||
if (track == null) {
|
||||
return false;
|
||||
}
|
||||
PermissionHolder.Identifier origin = node.metadata(InheritanceOriginMetadata.KEY).getOrigin();
|
||||
return track != null && origin.getType().equals(PermissionHolder.Identifier.GROUP_TYPE) && track.containsGroup(origin.getName());
|
||||
return origin.getType().equals(PermissionHolder.Identifier.GROUP_TYPE) && track.containsGroup(origin.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -250,8 +253,11 @@ public final class StandardStackElements {
|
||||
@Override
|
||||
public boolean shouldAccumulate(@NonNull ChatMetaType type, @NonNull ChatMetaNode<?, ?> node, @Nullable ChatMetaNode<?, ?> current) {
|
||||
Track track = this.plugin.getTrackManager().getIfLoaded(this.trackName);
|
||||
if (track == null) {
|
||||
return false;
|
||||
}
|
||||
PermissionHolder.Identifier origin = node.metadata(InheritanceOriginMetadata.KEY).getOrigin();
|
||||
return track != null && !track.containsGroup(origin.getName());
|
||||
return !(origin.getType().equals(PermissionHolder.Identifier.GROUP_TYPE) && track.containsGroup(origin.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -305,7 +311,7 @@ public final class StandardStackElements {
|
||||
@Override
|
||||
public boolean shouldAccumulate(@NonNull ChatMetaType type, @NonNull ChatMetaNode<?, ?> node, @Nullable ChatMetaNode<?, ?> current) {
|
||||
PermissionHolder.Identifier origin = node.metadata(InheritanceOriginMetadata.KEY).getOrigin();
|
||||
return !this.groupName.equals(origin.getName());
|
||||
return !(origin.getType().equals(PermissionHolder.Identifier.GROUP_TYPE) && this.groupName.equals(origin.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.result;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public abstract class AbstractResult<T, N extends Node, S extends AbstractResult<T, N, S>> implements Result<T, N> {
|
||||
|
||||
/** The node that caused the result */
|
||||
protected final N node;
|
||||
/** A reference to another result that this one overrides */
|
||||
protected S overriddenResult;
|
||||
|
||||
public AbstractResult(N node, S overriddenResult) {
|
||||
this.node = node;
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable N node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public final @Nullable S overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public final void setOverriddenResult(S overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-22
@@ -25,30 +25,23 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.result;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.WeightNode;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the result of an integer meta lookup
|
||||
*
|
||||
* @param <N> the node type
|
||||
*/
|
||||
public final class IntegerResult<N extends Node> implements Result<Integer, N> {
|
||||
public final class IntegerResult<N extends Node> extends AbstractResult<Integer, N, IntegerResult<N>> {
|
||||
|
||||
/** The result */
|
||||
private final int result;
|
||||
/** The node that caused the result */
|
||||
private final N node;
|
||||
/** A reference to another result that this one overrides */
|
||||
private IntegerResult<N> overriddenResult;
|
||||
|
||||
public IntegerResult(int result, N node, IntegerResult<N> overriddenResult) {
|
||||
super(node, overriddenResult);
|
||||
this.result = result;
|
||||
this.node = node;
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,19 +66,6 @@ public final class IntegerResult<N extends Node> implements Result<Integer, N> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable N node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public @Nullable IntegerResult<N> overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public void setOverriddenResult(IntegerResult<N> overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return this == NULL_RESULT;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.result;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
@@ -36,19 +35,14 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
*
|
||||
* @param <N> the node type
|
||||
*/
|
||||
public final class StringResult<N extends Node> implements Result<String, N> {
|
||||
public final class StringResult<N extends Node> extends AbstractResult<String, N, StringResult<N>> {
|
||||
|
||||
/** The result, nullable */
|
||||
private final String result;
|
||||
/** The node that caused the result */
|
||||
private final N node;
|
||||
/** A reference to another result that this one overrides */
|
||||
private StringResult<N> overriddenResult;
|
||||
|
||||
public StringResult(String result, N node, StringResult<N> overriddenResult) {
|
||||
super(node, overriddenResult);
|
||||
this.result = result;
|
||||
this.node = node;
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,19 +50,6 @@ public final class StringResult<N extends Node> implements Result<String, N> {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable N node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public @Nullable StringResult<N> overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public void setOverriddenResult(StringResult<N> overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
public StringResult<N> copy() {
|
||||
return new StringResult<>(this.result, this.node, this.overriddenResult);
|
||||
}
|
||||
|
||||
+2
-20
@@ -27,7 +27,6 @@ package me.lucko.luckperms.common.cacheddata.result;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
@@ -36,20 +35,16 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
/**
|
||||
* Represents the result of a {@link PermissionCalculator} lookup.
|
||||
*/
|
||||
public final class TristateResult implements Result<Tristate, Node> {
|
||||
public final class TristateResult extends AbstractResult<Tristate, Node, TristateResult> {
|
||||
|
||||
/** The result */
|
||||
private final Tristate result;
|
||||
/** The node that caused the result */
|
||||
private final Node node;
|
||||
/** The permission processor that provided the result */
|
||||
private final Class<? extends PermissionProcessor> processorClass;
|
||||
/** A reference to another result that this one overrides */
|
||||
private TristateResult overriddenResult;
|
||||
|
||||
private TristateResult(Tristate result, Node node, Class<? extends PermissionProcessor> processorClass) {
|
||||
super(node, null);
|
||||
this.result = result;
|
||||
this.node = node;
|
||||
this.processorClass = processorClass;
|
||||
}
|
||||
|
||||
@@ -58,11 +53,6 @@ public final class TristateResult implements Result<Tristate, Node> {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Node node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public @Nullable Class<? extends PermissionProcessor> processorClass() {
|
||||
return this.processorClass;
|
||||
}
|
||||
@@ -79,14 +69,6 @@ public final class TristateResult implements Result<Tristate, Node> {
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable TristateResult overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public void setOverriddenResult(TristateResult overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TristateResult(" +
|
||||
|
||||
@@ -79,6 +79,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -101,7 +102,7 @@ public class CommandManager {
|
||||
.build()
|
||||
);
|
||||
private final AtomicBoolean executingCommand = new AtomicBoolean(false);
|
||||
private final ExpiringSet<UUID> playerRateLimit = new ExpiringSet<>(500, TimeUnit.MILLISECONDS);
|
||||
private final Set<UUID> playerRateLimit = ExpiringSet.newExpiringSet(500, TimeUnit.MILLISECONDS);
|
||||
private final TabCompletions tabCompletions;
|
||||
private final Map<String, Command<?>> mainCommands;
|
||||
|
||||
@@ -159,6 +160,15 @@ public class CommandManager {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
boolean commandsDisabled = sender.isConsole()
|
||||
? this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_CONSOLE)
|
||||
: this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_PLAYERS);
|
||||
|
||||
if (commandsDisabled) {
|
||||
Message.COMMANDS_DISABLED.send(sender);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
SchedulerAdapter scheduler = this.plugin.getBootstrap().getScheduler();
|
||||
List<String> argsCopy = new ArrayList<>(args);
|
||||
|
||||
@@ -285,6 +295,14 @@ public class CommandManager {
|
||||
}
|
||||
|
||||
public List<String> tabCompleteCommand(Sender sender, List<String> arguments) {
|
||||
boolean commandsDisabled = sender.isConsole()
|
||||
? this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_CONSOLE)
|
||||
: this.plugin.getConfiguration().get(ConfigKeys.DISABLE_LUCKPERMS_COMMANDS_PLAYERS);
|
||||
|
||||
if (commandsDisabled) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
applyConvenienceAliases(arguments, false);
|
||||
|
||||
final List<Command<?>> mains = this.mainCommands.values().stream()
|
||||
|
||||
+2
-1
@@ -31,6 +31,7 @@ import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
@@ -66,7 +67,7 @@ public abstract class ChildCommand<T> extends Command<T> {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
builder.append(Component.text(" - ", NamedTextColor.DARK_AQUA))
|
||||
.append(Component.join(Component.space(), argUsages))
|
||||
.append(Component.join(JoinConfiguration.separator(Component.space()), argUsages))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -35,6 +35,7 @@ import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
@@ -114,7 +115,7 @@ public abstract class GenericChildCommand {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
builder.append(Component.text(" - ", NamedTextColor.DARK_AQUA))
|
||||
.append(Component.join(Component.space(), argUsages))
|
||||
.append(Component.join(JoinConfiguration.separator(Component.space()), argUsages))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+42
-27
@@ -86,39 +86,44 @@ public abstract class ParentCommand<T, I> extends Command<Void> {
|
||||
return;
|
||||
}
|
||||
|
||||
final String targetArgument = args.get(0);
|
||||
I targetId = null;
|
||||
if (this.type == Type.TAKES_ARGUMENT_FOR_TARGET) {
|
||||
targetId = parseTarget(targetArgument, plugin, sender);
|
||||
if (this.type == Type.TARGETED) {
|
||||
final String targetArgument = args.get(0);
|
||||
I targetId = parseTarget(targetArgument, plugin, sender);
|
||||
if (targetId == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ReentrantLock lock = getLockForTarget(targetId);
|
||||
lock.lock();
|
||||
try {
|
||||
T target = getTarget(targetId, plugin, sender);
|
||||
if (target == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ReentrantLock lock = getLockForTarget(targetId);
|
||||
lock.lock();
|
||||
try {
|
||||
sub.execute(plugin, sender, target, args.subList(this.type.minArgs, args.size()), label);
|
||||
T target = getTarget(targetId, plugin, sender);
|
||||
if (target == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
sub.execute(plugin, sender, target, args.subList(this.type.minArgs, args.size()), label);
|
||||
} catch (CommandException e) {
|
||||
e.handle(sender, label, sub);
|
||||
}
|
||||
|
||||
cleanup(target, plugin);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
sub.execute(plugin, sender, null, args.subList(this.type.minArgs, args.size()), label);
|
||||
} catch (CommandException e) {
|
||||
e.handle(sender, label, sub);
|
||||
}
|
||||
|
||||
cleanup(target, plugin);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> tabComplete(LuckPermsPlugin plugin, Sender sender, ArgumentList args) {
|
||||
switch (this.type) {
|
||||
case TAKES_ARGUMENT_FOR_TARGET:
|
||||
case TARGETED:
|
||||
return TabCompleter.create()
|
||||
.at(0, CompletionSupplier.startsWith(() -> getTargets(plugin).stream()))
|
||||
.at(1, CompletionSupplier.startsWith(() -> getChildren().stream()
|
||||
@@ -133,7 +138,7 @@ public abstract class ParentCommand<T, I> extends Command<Void> {
|
||||
.orElse(Collections.emptyList())
|
||||
)
|
||||
.complete(args);
|
||||
case NO_TARGET_ARGUMENT:
|
||||
case NOT_TARGETED:
|
||||
return TabCompleter.create()
|
||||
.at(0, CompletionSupplier.startsWith(() -> getChildren().stream()
|
||||
.filter(s -> s.isAuthorized(sender))
|
||||
@@ -178,21 +183,31 @@ public abstract class ParentCommand<T, I> extends Command<Void> {
|
||||
return getChildren().stream().anyMatch(sc -> sc.isAuthorized(sender));
|
||||
}
|
||||
|
||||
protected abstract List<String> getTargets(LuckPermsPlugin plugin);
|
||||
protected List<String> getTargets(LuckPermsPlugin plugin) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected abstract I parseTarget(String target, LuckPermsPlugin plugin, Sender sender);
|
||||
protected I parseTarget(String target, LuckPermsPlugin plugin, Sender sender) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected abstract ReentrantLock getLockForTarget(I target);
|
||||
protected ReentrantLock getLockForTarget(I target) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected abstract T getTarget(I target, LuckPermsPlugin plugin, Sender sender);
|
||||
protected T getTarget(I target, LuckPermsPlugin plugin, Sender sender) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected abstract void cleanup(T t, LuckPermsPlugin plugin);
|
||||
protected void cleanup(T t, LuckPermsPlugin plugin) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
// e.g. /lp log sub-command....
|
||||
NO_TARGET_ARGUMENT(0),
|
||||
NOT_TARGETED(0),
|
||||
// e.g. /lp user <USER> sub-command....
|
||||
TAKES_ARGUMENT_FOR_TARGET(1);
|
||||
TARGETED(1);
|
||||
|
||||
private final int cmdIndex;
|
||||
private final int minArgs;
|
||||
|
||||
+2
-1
@@ -33,6 +33,7 @@ import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
@@ -70,7 +71,7 @@ public abstract class SingleCommand extends Command<Void> {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
builder.append(Component.text(" - ", NamedTextColor.DARK_AQUA))
|
||||
.append(Component.join(Component.space(), argUsages))
|
||||
.append(Component.join(JoinConfiguration.separator(Component.space()), argUsages))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+137
-131
@@ -32,143 +32,143 @@ import me.lucko.luckperms.common.sender.Sender;
|
||||
*/
|
||||
public enum CommandPermission {
|
||||
|
||||
SYNC("sync", Type.NONE),
|
||||
INFO("info", Type.NONE),
|
||||
EDITOR("editor", Type.NONE),
|
||||
VERBOSE("verbose", Type.NONE),
|
||||
VERBOSE_COMMAND_OTHERS("verbose.command.others", Type.NONE),
|
||||
TREE("tree", Type.NONE),
|
||||
SEARCH("search", Type.NONE),
|
||||
IMPORT("import", Type.NONE),
|
||||
EXPORT("export", Type.NONE),
|
||||
RELOAD_CONFIG("reloadconfig", Type.NONE),
|
||||
BULK_UPDATE("bulkupdate", Type.NONE),
|
||||
APPLY_EDITS("applyedits", Type.NONE),
|
||||
TRUST_EDITOR("trusteditor", Type.NONE),
|
||||
TRANSLATIONS("translations", Type.NONE),
|
||||
SYNC("sync", Type.NONE, true),
|
||||
INFO("info", Type.NONE, true),
|
||||
EDITOR("editor", Type.NONE, true),
|
||||
VERBOSE("verbose", Type.NONE, true),
|
||||
VERBOSE_COMMAND_OTHERS("verbose.command.others", Type.NONE, false),
|
||||
TREE("tree", Type.NONE, true),
|
||||
SEARCH("search", Type.NONE, true),
|
||||
IMPORT("import", Type.NONE, false),
|
||||
EXPORT("export", Type.NONE, true),
|
||||
RELOAD_CONFIG("reloadconfig", Type.NONE, true),
|
||||
BULK_UPDATE("bulkupdate", Type.NONE, false),
|
||||
APPLY_EDITS("applyedits", Type.NONE, false),
|
||||
TRUST_EDITOR("trusteditor", Type.NONE, false),
|
||||
TRANSLATIONS("translations", Type.NONE, true),
|
||||
|
||||
CREATE_GROUP("creategroup", Type.NONE),
|
||||
DELETE_GROUP("deletegroup", Type.NONE),
|
||||
LIST_GROUPS("listgroups", Type.NONE),
|
||||
CREATE_GROUP("creategroup", Type.NONE, false),
|
||||
DELETE_GROUP("deletegroup", Type.NONE, false),
|
||||
LIST_GROUPS("listgroups", Type.NONE, true),
|
||||
|
||||
CREATE_TRACK("createtrack", Type.NONE),
|
||||
DELETE_TRACK("deletetrack", Type.NONE),
|
||||
LIST_TRACKS("listtracks", Type.NONE),
|
||||
CREATE_TRACK("createtrack", Type.NONE, false),
|
||||
DELETE_TRACK("deletetrack", Type.NONE, false),
|
||||
LIST_TRACKS("listtracks", Type.NONE, true),
|
||||
|
||||
USER_INFO("info", Type.USER),
|
||||
USER_PERM_INFO("permission.info", Type.USER),
|
||||
USER_PERM_SET("permission.set", Type.USER),
|
||||
USER_PERM_UNSET("permission.unset", Type.USER),
|
||||
USER_PERM_SET_TEMP("permission.settemp", Type.USER),
|
||||
USER_PERM_UNSET_TEMP("permission.unsettemp", Type.USER),
|
||||
USER_PERM_CHECK("permission.check", Type.USER),
|
||||
USER_PERM_CLEAR("permission.clear", Type.USER),
|
||||
USER_PARENT_INFO("parent.info", Type.USER),
|
||||
USER_PARENT_SET("parent.set", Type.USER),
|
||||
USER_PARENT_SET_TRACK("parent.settrack", Type.USER),
|
||||
USER_PARENT_ADD("parent.add", Type.USER),
|
||||
USER_PARENT_REMOVE("parent.remove", Type.USER),
|
||||
USER_PARENT_ADD_TEMP("parent.addtemp", Type.USER),
|
||||
USER_PARENT_REMOVE_TEMP("parent.removetemp", Type.USER),
|
||||
USER_PARENT_CLEAR("parent.clear", Type.USER),
|
||||
USER_PARENT_CLEAR_TRACK("parent.cleartrack", Type.USER),
|
||||
USER_PARENT_SWITCHPRIMARYGROUP("parent.switchprimarygroup", Type.USER),
|
||||
USER_META_INFO("meta.info", Type.USER),
|
||||
USER_META_SET("meta.set", Type.USER),
|
||||
USER_META_UNSET("meta.unset", Type.USER),
|
||||
USER_META_SET_TEMP("meta.settemp", Type.USER),
|
||||
USER_META_UNSET_TEMP("meta.unsettemp", Type.USER),
|
||||
USER_META_ADD_PREFIX("meta.addprefix", Type.USER),
|
||||
USER_META_ADD_SUFFIX("meta.addsuffix", Type.USER),
|
||||
USER_META_SET_PREFIX("meta.setprefix", Type.USER),
|
||||
USER_META_SET_SUFFIX("meta.setsuffix", Type.USER),
|
||||
USER_META_REMOVE_PREFIX("meta.removeprefix", Type.USER),
|
||||
USER_META_REMOVE_SUFFIX("meta.removesuffix", Type.USER),
|
||||
USER_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.USER),
|
||||
USER_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.USER),
|
||||
USER_META_SET_TEMP_PREFIX("meta.settempprefix", Type.USER),
|
||||
USER_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.USER),
|
||||
USER_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.USER),
|
||||
USER_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.USER),
|
||||
USER_META_CLEAR("meta.clear", Type.USER),
|
||||
USER_EDITOR("editor", Type.USER),
|
||||
USER_SHOW_TRACKS("showtracks", Type.USER),
|
||||
USER_PROMOTE("promote", Type.USER),
|
||||
USER_DEMOTE("demote", Type.USER),
|
||||
USER_CLEAR("clear", Type.USER),
|
||||
USER_CLONE("clone", Type.USER),
|
||||
USER_INFO("info", Type.USER, true),
|
||||
USER_PERM_INFO("permission.info", Type.USER, true),
|
||||
USER_PERM_SET("permission.set", Type.USER, false),
|
||||
USER_PERM_UNSET("permission.unset", Type.USER, false),
|
||||
USER_PERM_SET_TEMP("permission.settemp", Type.USER, false),
|
||||
USER_PERM_UNSET_TEMP("permission.unsettemp", Type.USER, false),
|
||||
USER_PERM_CHECK("permission.check", Type.USER, true),
|
||||
USER_PERM_CLEAR("permission.clear", Type.USER, false),
|
||||
USER_PARENT_INFO("parent.info", Type.USER, true),
|
||||
USER_PARENT_SET("parent.set", Type.USER, false),
|
||||
USER_PARENT_SET_TRACK("parent.settrack", Type.USER, false),
|
||||
USER_PARENT_ADD("parent.add", Type.USER, false),
|
||||
USER_PARENT_REMOVE("parent.remove", Type.USER, false),
|
||||
USER_PARENT_ADD_TEMP("parent.addtemp", Type.USER, false),
|
||||
USER_PARENT_REMOVE_TEMP("parent.removetemp", Type.USER, false),
|
||||
USER_PARENT_CLEAR("parent.clear", Type.USER, false),
|
||||
USER_PARENT_CLEAR_TRACK("parent.cleartrack", Type.USER, false),
|
||||
USER_PARENT_SWITCHPRIMARYGROUP("parent.switchprimarygroup", Type.USER, false),
|
||||
USER_META_INFO("meta.info", Type.USER, true),
|
||||
USER_META_SET("meta.set", Type.USER, false),
|
||||
USER_META_UNSET("meta.unset", Type.USER, false),
|
||||
USER_META_SET_TEMP("meta.settemp", Type.USER, false),
|
||||
USER_META_UNSET_TEMP("meta.unsettemp", Type.USER, false),
|
||||
USER_META_ADD_PREFIX("meta.addprefix", Type.USER, false),
|
||||
USER_META_ADD_SUFFIX("meta.addsuffix", Type.USER, false),
|
||||
USER_META_SET_PREFIX("meta.setprefix", Type.USER, false),
|
||||
USER_META_SET_SUFFIX("meta.setsuffix", Type.USER, false),
|
||||
USER_META_REMOVE_PREFIX("meta.removeprefix", Type.USER, false),
|
||||
USER_META_REMOVE_SUFFIX("meta.removesuffix", Type.USER, false),
|
||||
USER_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.USER, false),
|
||||
USER_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.USER, false),
|
||||
USER_META_SET_TEMP_PREFIX("meta.settempprefix", Type.USER, false),
|
||||
USER_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.USER, false),
|
||||
USER_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.USER, false),
|
||||
USER_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.USER, false),
|
||||
USER_META_CLEAR("meta.clear", Type.USER, false),
|
||||
USER_EDITOR("editor", Type.USER, true),
|
||||
USER_SHOW_TRACKS("showtracks", Type.USER, true),
|
||||
USER_PROMOTE("promote", Type.USER, false),
|
||||
USER_DEMOTE("demote", Type.USER, false),
|
||||
USER_CLEAR("clear", Type.USER, false),
|
||||
USER_CLONE("clone", Type.USER, false),
|
||||
|
||||
GROUP_INFO("info", Type.GROUP),
|
||||
GROUP_PERM_INFO("permission.info", Type.GROUP),
|
||||
GROUP_PERM_SET("permission.set", Type.GROUP),
|
||||
GROUP_PERM_UNSET("permission.unset", Type.GROUP),
|
||||
GROUP_PERM_SET_TEMP("permission.settemp", Type.GROUP),
|
||||
GROUP_PERM_UNSET_TEMP("permission.unsettemp", Type.GROUP),
|
||||
GROUP_PERM_CHECK("permission.check", Type.GROUP),
|
||||
GROUP_PERM_CLEAR("permission.clear", Type.GROUP),
|
||||
GROUP_PARENT_INFO("parent.info", Type.GROUP),
|
||||
GROUP_PARENT_SET("parent.set", Type.GROUP),
|
||||
GROUP_PARENT_SET_TRACK("parent.settrack", Type.GROUP),
|
||||
GROUP_PARENT_ADD("parent.add", Type.GROUP),
|
||||
GROUP_PARENT_REMOVE("parent.remove", Type.GROUP),
|
||||
GROUP_PARENT_ADD_TEMP("parent.addtemp", Type.GROUP),
|
||||
GROUP_PARENT_REMOVE_TEMP("parent.removetemp", Type.GROUP),
|
||||
GROUP_PARENT_CLEAR("parent.clear", Type.GROUP),
|
||||
GROUP_PARENT_CLEAR_TRACK("parent.cleartrack", Type.GROUP),
|
||||
GROUP_META_INFO("meta.info", Type.GROUP),
|
||||
GROUP_META_SET("meta.set", Type.GROUP),
|
||||
GROUP_META_UNSET("meta.unset", Type.GROUP),
|
||||
GROUP_META_SET_TEMP("meta.settemp", Type.GROUP),
|
||||
GROUP_META_UNSET_TEMP("meta.unsettemp", Type.GROUP),
|
||||
GROUP_META_ADD_PREFIX("meta.addprefix", Type.GROUP),
|
||||
GROUP_META_ADD_SUFFIX("meta.addsuffix", Type.GROUP),
|
||||
GROUP_META_SET_PREFIX("meta.setprefix", Type.GROUP),
|
||||
GROUP_META_SET_SUFFIX("meta.setsuffix", Type.GROUP),
|
||||
GROUP_META_REMOVE_PREFIX("meta.removeprefix", Type.GROUP),
|
||||
GROUP_META_REMOVE_SUFFIX("meta.removesuffix", Type.GROUP),
|
||||
GROUP_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.GROUP),
|
||||
GROUP_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.GROUP),
|
||||
GROUP_META_SET_TEMP_PREFIX("meta.settempprefix", Type.GROUP),
|
||||
GROUP_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.GROUP),
|
||||
GROUP_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.GROUP),
|
||||
GROUP_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.GROUP),
|
||||
GROUP_META_CLEAR("meta.clear", Type.GROUP),
|
||||
GROUP_EDITOR("editor", Type.GROUP),
|
||||
GROUP_LIST_MEMBERS("listmembers", Type.GROUP),
|
||||
GROUP_SHOW_TRACKS("showtracks", Type.GROUP),
|
||||
GROUP_SET_WEIGHT("setweight", Type.GROUP),
|
||||
GROUP_SET_DISPLAY_NAME("setdisplayname", Type.GROUP),
|
||||
GROUP_CLEAR("clear", Type.GROUP),
|
||||
GROUP_RENAME("rename", Type.GROUP),
|
||||
GROUP_CLONE("clone", Type.GROUP),
|
||||
GROUP_INFO("info", Type.GROUP, true),
|
||||
GROUP_PERM_INFO("permission.info", Type.GROUP, true),
|
||||
GROUP_PERM_SET("permission.set", Type.GROUP, false),
|
||||
GROUP_PERM_UNSET("permission.unset", Type.GROUP, false),
|
||||
GROUP_PERM_SET_TEMP("permission.settemp", Type.GROUP, false),
|
||||
GROUP_PERM_UNSET_TEMP("permission.unsettemp", Type.GROUP, false),
|
||||
GROUP_PERM_CHECK("permission.check", Type.GROUP, true),
|
||||
GROUP_PERM_CLEAR("permission.clear", Type.GROUP, false),
|
||||
GROUP_PARENT_INFO("parent.info", Type.GROUP, true),
|
||||
GROUP_PARENT_SET("parent.set", Type.GROUP, false),
|
||||
GROUP_PARENT_SET_TRACK("parent.settrack", Type.GROUP, false),
|
||||
GROUP_PARENT_ADD("parent.add", Type.GROUP, false),
|
||||
GROUP_PARENT_REMOVE("parent.remove", Type.GROUP, false),
|
||||
GROUP_PARENT_ADD_TEMP("parent.addtemp", Type.GROUP, false),
|
||||
GROUP_PARENT_REMOVE_TEMP("parent.removetemp", Type.GROUP, false),
|
||||
GROUP_PARENT_CLEAR("parent.clear", Type.GROUP, false),
|
||||
GROUP_PARENT_CLEAR_TRACK("parent.cleartrack", Type.GROUP, false),
|
||||
GROUP_META_INFO("meta.info", Type.GROUP, true),
|
||||
GROUP_META_SET("meta.set", Type.GROUP, false),
|
||||
GROUP_META_UNSET("meta.unset", Type.GROUP, false),
|
||||
GROUP_META_SET_TEMP("meta.settemp", Type.GROUP, false),
|
||||
GROUP_META_UNSET_TEMP("meta.unsettemp", Type.GROUP, false),
|
||||
GROUP_META_ADD_PREFIX("meta.addprefix", Type.GROUP, false),
|
||||
GROUP_META_ADD_SUFFIX("meta.addsuffix", Type.GROUP, false),
|
||||
GROUP_META_SET_PREFIX("meta.setprefix", Type.GROUP, false),
|
||||
GROUP_META_SET_SUFFIX("meta.setsuffix", Type.GROUP, false),
|
||||
GROUP_META_REMOVE_PREFIX("meta.removeprefix", Type.GROUP, false),
|
||||
GROUP_META_REMOVE_SUFFIX("meta.removesuffix", Type.GROUP, false),
|
||||
GROUP_META_ADD_TEMP_PREFIX("meta.addtempprefix", Type.GROUP, false),
|
||||
GROUP_META_ADD_TEMP_SUFFIX("meta.addtempsuffix", Type.GROUP, false),
|
||||
GROUP_META_SET_TEMP_PREFIX("meta.settempprefix", Type.GROUP, false),
|
||||
GROUP_META_SET_TEMP_SUFFIX("meta.settempsuffix", Type.GROUP, false),
|
||||
GROUP_META_REMOVE_TEMP_PREFIX("meta.removetempprefix", Type.GROUP, false),
|
||||
GROUP_META_REMOVE_TEMP_SUFFIX("meta.removetempsuffix", Type.GROUP, false),
|
||||
GROUP_META_CLEAR("meta.clear", Type.GROUP, false),
|
||||
GROUP_EDITOR("editor", Type.GROUP, true),
|
||||
GROUP_LIST_MEMBERS("listmembers", Type.GROUP, true),
|
||||
GROUP_SHOW_TRACKS("showtracks", Type.GROUP, true),
|
||||
GROUP_SET_WEIGHT("setweight", Type.GROUP, false),
|
||||
GROUP_SET_DISPLAY_NAME("setdisplayname", Type.GROUP, false),
|
||||
GROUP_CLEAR("clear", Type.GROUP, false),
|
||||
GROUP_RENAME("rename", Type.GROUP, false),
|
||||
GROUP_CLONE("clone", Type.GROUP, false),
|
||||
|
||||
TRACK_INFO("info", Type.TRACK),
|
||||
TRACK_EDITOR("editor", Type.TRACK),
|
||||
TRACK_APPEND("append", Type.TRACK),
|
||||
TRACK_INSERT("insert", Type.TRACK),
|
||||
TRACK_REMOVE("remove", Type.TRACK),
|
||||
TRACK_CLEAR("clear", Type.TRACK),
|
||||
TRACK_RENAME("rename", Type.TRACK),
|
||||
TRACK_CLONE("clone", Type.TRACK),
|
||||
TRACK_INFO("info", Type.TRACK, true),
|
||||
TRACK_EDITOR("editor", Type.TRACK, true),
|
||||
TRACK_APPEND("append", Type.TRACK, false),
|
||||
TRACK_INSERT("insert", Type.TRACK, false),
|
||||
TRACK_REMOVE("remove", Type.TRACK, false),
|
||||
TRACK_CLEAR("clear", Type.TRACK, false),
|
||||
TRACK_RENAME("rename", Type.TRACK, false),
|
||||
TRACK_CLONE("clone", Type.TRACK, false),
|
||||
|
||||
LOG_RECENT("recent", Type.LOG),
|
||||
LOG_USER_HISTORY("userhistory", Type.LOG),
|
||||
LOG_GROUP_HISTORY("grouphistory", Type.LOG),
|
||||
LOG_TRACK_HISTORY("trackhistory", Type.LOG),
|
||||
LOG_SEARCH("search", Type.LOG),
|
||||
LOG_NOTIFY("notify", Type.LOG),
|
||||
LOG_RECENT("recent", Type.LOG, true),
|
||||
LOG_USER_HISTORY("userhistory", Type.LOG, true),
|
||||
LOG_GROUP_HISTORY("grouphistory", Type.LOG, true),
|
||||
LOG_TRACK_HISTORY("trackhistory", Type.LOG, true),
|
||||
LOG_SEARCH("search", Type.LOG, true),
|
||||
LOG_NOTIFY("notify", Type.LOG, true),
|
||||
|
||||
SPONGE_PERMISSION_INFO("permission.info", Type.SPONGE),
|
||||
SPONGE_PERMISSION_SET("permission.set", Type.SPONGE),
|
||||
SPONGE_PERMISSION_CLEAR("permission.clear", Type.SPONGE),
|
||||
SPONGE_PARENT_INFO("parent.info", Type.SPONGE),
|
||||
SPONGE_PARENT_ADD("parent.add", Type.SPONGE),
|
||||
SPONGE_PARENT_REMOVE("parent.remove", Type.SPONGE),
|
||||
SPONGE_PARENT_CLEAR("parent.clear", Type.SPONGE),
|
||||
SPONGE_OPTION_INFO("option.info", Type.SPONGE),
|
||||
SPONGE_OPTION_SET("option.set", Type.SPONGE),
|
||||
SPONGE_OPTION_UNSET("option.unset", Type.SPONGE),
|
||||
SPONGE_OPTION_CLEAR("option.clear", Type.SPONGE);
|
||||
SPONGE_PERMISSION_INFO("permission.info", Type.SPONGE, true),
|
||||
SPONGE_PERMISSION_SET("permission.set", Type.SPONGE, false),
|
||||
SPONGE_PERMISSION_CLEAR("permission.clear", Type.SPONGE, false),
|
||||
SPONGE_PARENT_INFO("parent.info", Type.SPONGE, true),
|
||||
SPONGE_PARENT_ADD("parent.add", Type.SPONGE, false),
|
||||
SPONGE_PARENT_REMOVE("parent.remove", Type.SPONGE, false),
|
||||
SPONGE_PARENT_CLEAR("parent.clear", Type.SPONGE, false),
|
||||
SPONGE_OPTION_INFO("option.info", Type.SPONGE, true),
|
||||
SPONGE_OPTION_SET("option.set", Type.SPONGE, false),
|
||||
SPONGE_OPTION_UNSET("option.unset", Type.SPONGE, false),
|
||||
SPONGE_OPTION_CLEAR("option.clear", Type.SPONGE, false);
|
||||
|
||||
public static final String ROOT = "luckperms.";
|
||||
|
||||
@@ -176,9 +176,11 @@ public enum CommandPermission {
|
||||
private final String permission;
|
||||
|
||||
private final Type type;
|
||||
private final boolean readOnly;
|
||||
|
||||
CommandPermission(String node, Type type) {
|
||||
CommandPermission(String node, Type type, boolean readOnly) {
|
||||
this.type = type;
|
||||
this.readOnly = readOnly;
|
||||
|
||||
if (type == Type.NONE) {
|
||||
this.node = node;
|
||||
@@ -205,6 +207,10 @@ public enum CommandPermission {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return this.readOnly;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
||||
NONE(null),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ public class GroupParentCommand extends ParentCommand<Group, String> {
|
||||
.build(key -> new ReentrantLock());
|
||||
|
||||
public GroupParentCommand() {
|
||||
super(CommandSpec.GROUP, "Group", Type.TAKES_ARGUMENT_FOR_TARGET, ImmutableList.<Command<Group>>builder()
|
||||
super(CommandSpec.GROUP, "Group", Type.TARGETED, ImmutableList.<Command<Group>>builder()
|
||||
.add(new GroupInfo())
|
||||
.add(new CommandPermission<>(HolderType.GROUP))
|
||||
.add(new CommandParent<>(HolderType.GROUP))
|
||||
|
||||
@@ -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<Group> {
|
||||
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 {
|
||||
|
||||
@@ -25,25 +25,26 @@
|
||||
|
||||
package me.lucko.luckperms.common.commands.log;
|
||||
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
|
||||
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.storage.misc.DataConstraints;
|
||||
import me.lucko.luckperms.common.util.Paginated;
|
||||
import me.lucko.luckperms.common.util.Predicates;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class LogGroupHistory extends ChildCommand<Log> {
|
||||
public class LogGroupHistory extends ChildCommand<Void> {
|
||||
private static final int ENTRIES_PER_PAGE = 10;
|
||||
|
||||
public LogGroupHistory() {
|
||||
@@ -51,44 +52,34 @@ public class LogGroupHistory extends ChildCommand<Log> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
|
||||
String group = args.get(0).toLowerCase(Locale.ROOT);
|
||||
if (!DataConstraints.GROUP_NAME_TEST.test(group)) {
|
||||
Message.GROUP_INVALID_ENTRY.send(sender, group);
|
||||
return;
|
||||
}
|
||||
|
||||
Paginated<LoggedAction> content = new Paginated<>(log.getGroupHistory(group));
|
||||
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 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<LoggedAction> 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<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
|
||||
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
|
||||
String name = entries.stream().findAny().get().value().getTarget().getName();
|
||||
Message.LOG_HISTORY_GROUP_HEADER.send(sender, name, page, maxPage);
|
||||
|
||||
for (Paginated.Entry<LoggedAction> e : entries) {
|
||||
for (LogPage.Entry<LoggedAction> e : entries) {
|
||||
Message.LOG_ENTRY.send(sender, e.position(), e.value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.commands.log;
|
||||
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
@@ -43,7 +42,7 @@ import net.luckperms.api.node.Node;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LogNotify extends ChildCommand<Log> {
|
||||
public class LogNotify extends ChildCommand<Void> {
|
||||
private static final String IGNORE_NODE = "luckperms.log.notify.ignoring";
|
||||
|
||||
public LogNotify() {
|
||||
@@ -83,7 +82,7 @@ public class LogNotify extends ChildCommand<Log> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
|
||||
if (sender.isConsole()) {
|
||||
Message.LOG_NOTIFY_CONSOLE.send(sender);
|
||||
return;
|
||||
|
||||
@@ -26,22 +26,13 @@
|
||||
package me.lucko.luckperms.common.commands.log;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.command.abstraction.Command;
|
||||
import me.lucko.luckperms.common.command.abstraction.ParentCommand;
|
||||
import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class LogParentCommand extends ParentCommand<Log, Void> {
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
public class LogParentCommand extends ParentCommand<Void, Void> {
|
||||
public LogParentCommand() {
|
||||
super(CommandSpec.LOG, "Log", Type.NO_TARGET_ARGUMENT, ImmutableList.<Command<Log>>builder()
|
||||
super(CommandSpec.LOG, "Log", Type.NOT_TARGETED, ImmutableList.<Command<Void>>builder()
|
||||
.add(new LogRecent())
|
||||
.add(new LogSearch())
|
||||
.add(new LogNotify())
|
||||
@@ -51,38 +42,4 @@ public class LogParentCommand extends ParentCommand<Log, Void> {
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReentrantLock getLockForTarget(Void target) {
|
||||
return this.lock; // all commands target the same log, so we share a lock between all "targets"
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Log getTarget(Void target, LuckPermsPlugin plugin, Sender sender) {
|
||||
Log log = plugin.getStorage().getLog().join();
|
||||
|
||||
if (log == null) {
|
||||
Message.LOG_LOAD_ERROR.send(sender);
|
||||
}
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup(Log log, LuckPermsPlugin plugin) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getTargets(LuckPermsPlugin plugin) {
|
||||
// should never be called if we specify Type.NO_TARGET_ARGUMENT in the constructor
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void parseTarget(String target, LuckPermsPlugin plugin, Sender sender) {
|
||||
// should never be called if we specify Type.NO_TARGET_ARGUMENT in the constructor
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,22 +25,23 @@
|
||||
|
||||
package me.lucko.luckperms.common.commands.log;
|
||||
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.util.Paginated;
|
||||
import me.lucko.luckperms.common.util.Predicates;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LogRecent extends ChildCommand<Log> {
|
||||
public class LogRecent extends ChildCommand<Void> {
|
||||
private static final int ENTRIES_PER_PAGE = 10;
|
||||
|
||||
public LogRecent() {
|
||||
@@ -48,39 +49,32 @@ public class LogRecent extends ChildCommand<Log> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
|
||||
if (args.isEmpty()) {
|
||||
// No page or user
|
||||
Paginated<LoggedAction> content = new Paginated<>(log.getContent());
|
||||
showLog(content.getMaxPages(ENTRIES_PER_PAGE), false, sender, content);
|
||||
return;
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
|
||||
int page = 1;
|
||||
UUID uuid = null;
|
||||
|
||||
if (!args.isEmpty()) {
|
||||
int pageNo = args.getIntOrDefault(0, Integer.MIN_VALUE);
|
||||
if (pageNo != Integer.MIN_VALUE) {
|
||||
page = pageNo;
|
||||
} else {
|
||||
uuid = args.getUserTarget(0, plugin, sender);
|
||||
if (uuid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
pageNo = args.getIntOrDefault(1, Integer.MIN_VALUE);
|
||||
if (pageNo != Integer.MIN_VALUE) {
|
||||
page = pageNo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int page = args.getIntOrDefault(0, Integer.MIN_VALUE);
|
||||
if (page != Integer.MIN_VALUE) {
|
||||
Paginated<LoggedAction> content = new Paginated<>(log.getContent());
|
||||
showLog(page, false, sender, content);
|
||||
return;
|
||||
}
|
||||
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, page);
|
||||
LogPage log = plugin.getStorage().getLogPage(uuid == null ? ActionFilters.all() : ActionFilters.source(uuid), pageParams).join();
|
||||
|
||||
// User and possibly page
|
||||
UUID uuid = args.getUserTarget(0, plugin, sender);
|
||||
if (uuid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Paginated<LoggedAction> content = new Paginated<>(log.getContent(uuid));
|
||||
page = args.getIntOrDefault(1, Integer.MIN_VALUE);
|
||||
if (page != Integer.MIN_VALUE) {
|
||||
showLog(page, true, sender, content);
|
||||
} else {
|
||||
showLog(content.getMaxPages(ENTRIES_PER_PAGE), true, sender, content);
|
||||
}
|
||||
}
|
||||
|
||||
private static void showLog(int page, boolean specificUser, Sender sender, Paginated<LoggedAction> log) {
|
||||
int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
|
||||
if (maxPage == 0) {
|
||||
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
|
||||
if (log.getTotalEntries() == 0) {
|
||||
Message.LOG_NO_ENTRIES.send(sender);
|
||||
return;
|
||||
}
|
||||
@@ -90,8 +84,8 @@ public class LogRecent extends ChildCommand<Log> {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
|
||||
if (specificUser) {
|
||||
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
|
||||
if (uuid != null) {
|
||||
String name = entries.stream().findAny().get().value().getSource().getName();
|
||||
if (name.contains("@")) {
|
||||
name = name.split("@")[0];
|
||||
@@ -101,8 +95,9 @@ public class LogRecent extends ChildCommand<Log> {
|
||||
Message.LOG_RECENT_HEADER.send(sender, page, maxPage);
|
||||
}
|
||||
|
||||
for (Paginated.Entry<LoggedAction> e : entries) {
|
||||
for (LogPage.Entry<LoggedAction> e : entries) {
|
||||
Message.LOG_ENTRY.send(sender, e.position(), e.value());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,21 +25,22 @@
|
||||
|
||||
package me.lucko.luckperms.common.commands.log;
|
||||
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.util.Paginated;
|
||||
import me.lucko.luckperms.common.util.Predicates;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LogSearch extends ChildCommand<Log> {
|
||||
public class LogSearch extends ChildCommand<Void> {
|
||||
private static final int ENTRIES_PER_PAGE = 10;
|
||||
|
||||
public LogSearch() {
|
||||
@@ -47,8 +48,8 @@ public class LogSearch extends ChildCommand<Log> {
|
||||
}
|
||||
|
||||
@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<Log> {
|
||||
}
|
||||
|
||||
final String query = String.join(" ", args);
|
||||
Paginated<LoggedAction> content = new Paginated<>(log.getSearch(query));
|
||||
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, page);
|
||||
LogPage log = plugin.getStorage().getLogPage(ActionFilters.search(query), pageParams).join();
|
||||
|
||||
if (page != Integer.MIN_VALUE) {
|
||||
showLog(page, query, sender, content);
|
||||
} else {
|
||||
showLog(content.getMaxPages(ENTRIES_PER_PAGE), query, sender, content);
|
||||
}
|
||||
}
|
||||
|
||||
private static void showLog(int page, String query, Sender sender, Paginated<LoggedAction> log) {
|
||||
int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
|
||||
if (maxPage == 0) {
|
||||
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
|
||||
if (log.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<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
|
||||
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
|
||||
Message.LOG_SEARCH_HEADER.send(sender, query, page, maxPage);
|
||||
|
||||
for (Paginated.Entry<LoggedAction> e : entries) {
|
||||
for (LogPage.Entry<LoggedAction> e : entries) {
|
||||
Message.LOG_ENTRY.send(sender, e.position(), e.value());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,25 +25,26 @@
|
||||
|
||||
package me.lucko.luckperms.common.commands.log;
|
||||
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
import me.lucko.luckperms.common.command.tabcomplete.TabCompleter;
|
||||
import me.lucko.luckperms.common.command.tabcomplete.TabCompletions;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.storage.misc.DataConstraints;
|
||||
import me.lucko.luckperms.common.util.Paginated;
|
||||
import me.lucko.luckperms.common.util.Predicates;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class LogTrackHistory extends ChildCommand<Log> {
|
||||
public class LogTrackHistory extends ChildCommand<Void> {
|
||||
private static final int ENTRIES_PER_PAGE = 10;
|
||||
|
||||
public LogTrackHistory() {
|
||||
@@ -51,44 +52,33 @@ public class LogTrackHistory extends ChildCommand<Log> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
|
||||
String track = args.get(0).toLowerCase(Locale.ROOT);
|
||||
if (!DataConstraints.TRACK_NAME_TEST.test(track)) {
|
||||
Message.TRACK_INVALID_ENTRY.send(sender, track);
|
||||
return;
|
||||
}
|
||||
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 1));
|
||||
LogPage log = plugin.getStorage().getLogPage(ActionFilters.track(track), pageParams).join();
|
||||
|
||||
Paginated<LoggedAction> content = new Paginated<>(log.getTrackHistory(track));
|
||||
int page = pageParams.pageNumber();
|
||||
int maxPage = pageParams.getMaxPage(log.getTotalEntries());
|
||||
|
||||
int page = args.getIntOrDefault(1, Integer.MIN_VALUE);
|
||||
if (page != Integer.MIN_VALUE) {
|
||||
showLog(page, sender, content);
|
||||
} else {
|
||||
showLog(content.getMaxPages(ENTRIES_PER_PAGE), sender, content);
|
||||
}
|
||||
}
|
||||
|
||||
private static void showLog(int page, Sender sender, Paginated<LoggedAction> log) {
|
||||
int maxPage = log.getMaxPages(ENTRIES_PER_PAGE);
|
||||
if (maxPage == 0) {
|
||||
if (log.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<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
|
||||
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
|
||||
String name = entries.stream().findAny().get().value().getTarget().getName();
|
||||
Message.LOG_HISTORY_TRACK_HEADER.send(sender, name, page, maxPage);
|
||||
|
||||
for (Paginated.Entry<LoggedAction> e : entries) {
|
||||
for (LogPage.Entry<LoggedAction> e : entries) {
|
||||
Message.LOG_ENTRY.send(sender, e.position(), e.value());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,22 +25,23 @@
|
||||
|
||||
package me.lucko.luckperms.common.commands.log;
|
||||
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LogPage;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.actionlog.filter.ActionFilters;
|
||||
import me.lucko.luckperms.common.command.abstraction.ChildCommand;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
import me.lucko.luckperms.common.command.utils.ArgumentList;
|
||||
import me.lucko.luckperms.common.filter.PageParameters;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.util.Paginated;
|
||||
import me.lucko.luckperms.common.util.Predicates;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LogUserHistory extends ChildCommand<Log> {
|
||||
public class LogUserHistory extends ChildCommand<Void> {
|
||||
private static final int ENTRIES_PER_PAGE = 10;
|
||||
|
||||
public LogUserHistory() {
|
||||
@@ -48,25 +49,19 @@ public class LogUserHistory extends ChildCommand<Log> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Log log, ArgumentList args, String label) {
|
||||
public void execute(LuckPermsPlugin plugin, Sender sender, Void ignored, ArgumentList args, String label) {
|
||||
UUID uuid = args.getUserTarget(0, plugin, sender);
|
||||
if (uuid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Paginated<LoggedAction> content = new Paginated<>(log.getUserHistory(uuid));
|
||||
PageParameters pageParams = new PageParameters(ENTRIES_PER_PAGE, args.getIntOrDefault(1, 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<LoggedAction> 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<Log> {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Paginated.Entry<LoggedAction>> entries = log.getPage(page, ENTRIES_PER_PAGE);
|
||||
List<LogPage.Entry<LoggedAction>> entries = log.getNumberedContent();
|
||||
String name = entries.stream().findAny().get().value().getTarget().getName();
|
||||
Message.LOG_HISTORY_USER_HEADER.send(sender, name, page, maxPage);
|
||||
|
||||
for (Paginated.Entry<LoggedAction> e : entries) {
|
||||
for (LogPage.Entry<LoggedAction> e : entries) {
|
||||
Message.LOG_ENTRY.send(sender, e.position(), e.value());
|
||||
}
|
||||
}
|
||||
|
||||
+12
-10
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Node> matcher = StandardNodeMatchers.of(Constraint.of(comparison, args.get(1)));
|
||||
ConstraintNodeMatcher<Node> 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<String, NodeEntry<T, Node>> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -53,7 +53,7 @@ public class TrackParentCommand extends ParentCommand<Track, String> {
|
||||
.build(key -> new ReentrantLock());
|
||||
|
||||
public TrackParentCommand() {
|
||||
super(CommandSpec.TRACK, "Track", Type.TAKES_ARGUMENT_FOR_TARGET, ImmutableList.<Command<Track>>builder()
|
||||
super(CommandSpec.TRACK, "Track", Type.TARGETED, ImmutableList.<Command<Track>>builder()
|
||||
.add(new TrackInfo())
|
||||
.add(new TrackEditor())
|
||||
.add(new TrackAppend())
|
||||
|
||||
@@ -62,7 +62,7 @@ public class UserParentCommand extends ParentCommand<User, UserIdentifier> {
|
||||
.build(key -> new ReentrantLock());
|
||||
|
||||
public UserParentCommand() {
|
||||
super(CommandSpec.USER, "User", Type.TAKES_ARGUMENT_FOR_TARGET, ImmutableList.<Command<User>>builder()
|
||||
super(CommandSpec.USER, "User", Type.TARGETED, ImmutableList.<Command<User>>builder()
|
||||
.add(new UserInfo())
|
||||
.add(new CommandPermission<>(HolderType.USER))
|
||||
.add(new CommandParent<>(HolderType.USER))
|
||||
|
||||
@@ -28,14 +28,14 @@ package me.lucko.luckperms.common.config;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.cacheddata.metastack.StandardStackElements;
|
||||
import me.lucko.luckperms.common.cacheddata.type.SimpleMetaValueSelector;
|
||||
import me.lucko.luckperms.common.config.generic.KeyedConfiguration;
|
||||
import me.lucko.luckperms.common.config.generic.key.ConfigKey;
|
||||
import me.lucko.luckperms.common.config.generic.key.SimpleConfigKey;
|
||||
import me.lucko.luckperms.common.context.calculator.WorldNameRewriter;
|
||||
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
|
||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.metastacking.StandardStackElements;
|
||||
import me.lucko.luckperms.common.model.PrimaryGroupHolder;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsBuilderImpl;
|
||||
@@ -246,6 +246,26 @@ public final class ConfigKeys {
|
||||
*/
|
||||
public static final ConfigKey<Boolean> REQUIRE_SENDER_GROUP_MEMBERSHIP_TO_MODIFY = booleanKey("require-sender-group-membership-to-modify", false);
|
||||
|
||||
/**
|
||||
* If the plugin is in read-only mode for players
|
||||
*/
|
||||
public static final ConfigKey<Boolean> READ_ONLY_MODE_PLAYERS = booleanKey("commands-read-only-mode.players", false);
|
||||
|
||||
/**
|
||||
* If the plugin is in read-only mode for the server console
|
||||
*/
|
||||
public static final ConfigKey<Boolean> READ_ONLY_MODE_CONSOLE = booleanKey("commands-read-only-mode.console", false);
|
||||
|
||||
/**
|
||||
* If LuckPerms commands are disabled for players
|
||||
*/
|
||||
public static final ConfigKey<Boolean> DISABLE_LUCKPERMS_COMMANDS_PLAYERS = booleanKey("disable-luckperms-commands.players", false);
|
||||
|
||||
/**
|
||||
* If LuckPerms commands are disabled for the server console
|
||||
*/
|
||||
public static final ConfigKey<Boolean> DISABLE_LUCKPERMS_COMMANDS_CONSOLE = booleanKey("disable-luckperms-commands.console", false);
|
||||
|
||||
/**
|
||||
* If wildcards are being applied
|
||||
*/
|
||||
@@ -370,16 +390,16 @@ public final class ConfigKeys {
|
||||
/**
|
||||
* Creates a new prefix MetaStack element based upon the configured values.
|
||||
*/
|
||||
public static final ConfigKey<MetaStackDefinition> PREFIX_FORMATTING_OPTIONS = key(l -> {
|
||||
List<String> format = l.getStringList("meta-formatting.prefix.format", new ArrayList<>());
|
||||
public static final ConfigKey<MetaStackDefinition> PREFIX_FORMATTING_OPTIONS = key(c -> {
|
||||
List<String> format = c.getStringList("meta-formatting.prefix.format", new ArrayList<>());
|
||||
if (format.isEmpty()) {
|
||||
format.add("highest");
|
||||
}
|
||||
String startSpacer = l.getString("meta-formatting.prefix.start-spacer", "");
|
||||
String middleSpacer = l.getString("meta-formatting.prefix.middle-spacer", " ");
|
||||
String endSpacer = l.getString("meta-formatting.prefix.end-spacer", "");
|
||||
String startSpacer = c.getString("meta-formatting.prefix.start-spacer", "");
|
||||
String middleSpacer = c.getString("meta-formatting.prefix.middle-spacer", " ");
|
||||
String endSpacer = c.getString("meta-formatting.prefix.end-spacer", "");
|
||||
DuplicateRemovalFunction duplicateRemovalFunction;
|
||||
switch (l.getString("meta-formatting.prefix.duplicates", "").toLowerCase(Locale.ROOT)) {
|
||||
switch (c.getString("meta-formatting.prefix.duplicates", "").toLowerCase(Locale.ROOT)) {
|
||||
case "first-only":
|
||||
duplicateRemovalFunction = DuplicateRemovalFunction.FIRST_ONLY;
|
||||
break;
|
||||
@@ -391,22 +411,22 @@ public final class ConfigKeys {
|
||||
break;
|
||||
}
|
||||
|
||||
return new SimpleMetaStackDefinition(StandardStackElements.parseList(l.getPlugin(), format), duplicateRemovalFunction, startSpacer, middleSpacer, endSpacer);
|
||||
return new SimpleMetaStackDefinition(StandardStackElements.parseList(c.getPlugin(), format), duplicateRemovalFunction, startSpacer, middleSpacer, endSpacer);
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a new suffix MetaStack element based upon the configured values.
|
||||
*/
|
||||
public static final ConfigKey<MetaStackDefinition> SUFFIX_FORMATTING_OPTIONS = key(l -> {
|
||||
List<String> format = l.getStringList("meta-formatting.suffix.format", new ArrayList<>());
|
||||
public static final ConfigKey<MetaStackDefinition> SUFFIX_FORMATTING_OPTIONS = key(c -> {
|
||||
List<String> format = c.getStringList("meta-formatting.suffix.format", new ArrayList<>());
|
||||
if (format.isEmpty()) {
|
||||
format.add("highest");
|
||||
}
|
||||
String startSpacer = l.getString("meta-formatting.suffix.start-spacer", "");
|
||||
String middleSpacer = l.getString("meta-formatting.suffix.middle-spacer", " ");
|
||||
String endSpacer = l.getString("meta-formatting.suffix.end-spacer", "");
|
||||
String startSpacer = c.getString("meta-formatting.suffix.start-spacer", "");
|
||||
String middleSpacer = c.getString("meta-formatting.suffix.middle-spacer", " ");
|
||||
String endSpacer = c.getString("meta-formatting.suffix.end-spacer", "");
|
||||
DuplicateRemovalFunction duplicateRemovalFunction;
|
||||
switch (l.getString("meta-formatting.suffix.duplicates", "").toLowerCase(Locale.ROOT)) {
|
||||
switch (c.getString("meta-formatting.suffix.duplicates", "").toLowerCase(Locale.ROOT)) {
|
||||
case "first-only":
|
||||
duplicateRemovalFunction = DuplicateRemovalFunction.FIRST_ONLY;
|
||||
break;
|
||||
@@ -418,7 +438,7 @@ public final class ConfigKeys {
|
||||
break;
|
||||
}
|
||||
|
||||
return new SimpleMetaStackDefinition(StandardStackElements.parseList(l.getPlugin(), format), duplicateRemovalFunction, startSpacer, middleSpacer, endSpacer);
|
||||
return new SimpleMetaStackDefinition(StandardStackElements.parseList(c.getPlugin(), format), duplicateRemovalFunction, startSpacer, middleSpacer, endSpacer);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -443,6 +463,11 @@ public final class ConfigKeys {
|
||||
.collect(ImmutableCollectors.toList());
|
||||
});
|
||||
|
||||
/**
|
||||
* If log should be posted synchronously to storage/messaging in commands
|
||||
*/
|
||||
public static final ConfigKey<Boolean> LOG_SYNCHRONOUSLY_IN_COMMANDS = booleanKey("log-synchronously-in-commands", false);
|
||||
|
||||
/**
|
||||
* If LuckPerms should automatically install translation bundles and periodically update them.
|
||||
*/
|
||||
@@ -580,6 +605,16 @@ public final class ConfigKeys {
|
||||
return c.getString("data.mongodb-connection-uri", c.getString("data.mongodb_connection_URI", ""));
|
||||
}));
|
||||
|
||||
/**
|
||||
* The REST storage URL
|
||||
*/
|
||||
public static final ConfigKey<String> REST_STORAGE_URL = notReloadable(stringKey("data.rest-url", "http://localhost:8080/"));
|
||||
|
||||
/**
|
||||
* The REST storage auth key
|
||||
*/
|
||||
public static final ConfigKey<String> REST_STORAGE_AUTH_KEY = notReloadable(stringKey("data.rest-auth-key", ""));
|
||||
|
||||
/**
|
||||
* The name of the storage method being used
|
||||
*/
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.config.generic.adapter;
|
||||
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Locale;
|
||||
|
||||
public class FileSecretConfigAdapter extends StringBasedConfigurationAdapter {
|
||||
private static final String PREFIX = "luckperms_";
|
||||
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final Path directory;
|
||||
|
||||
public FileSecretConfigAdapter(LuckPermsPlugin plugin, String directory) {
|
||||
this.plugin = plugin;
|
||||
this.directory = directory == null ? null : Paths.get(directory);
|
||||
}
|
||||
|
||||
public FileSecretConfigAdapter(LuckPermsPlugin plugin) {
|
||||
this(plugin, System.getenv("LUCKPERMS_FILE_SECRET_DIRECTORY"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable String resolveValue(String path) {
|
||||
if (this.directory == null) {
|
||||
return null; // not configured
|
||||
}
|
||||
|
||||
// e.g.
|
||||
// 'server' -> luckperms_server
|
||||
// 'data.table_prefix' -> luckperms_data_table_prefix
|
||||
String key = PREFIX + path.toLowerCase(Locale.ROOT)
|
||||
.replace('-', '_')
|
||||
.replace('.', '_');
|
||||
|
||||
Path resolvedFile = this.directory.resolve(key);
|
||||
|
||||
String value;
|
||||
try {
|
||||
value = new String(Files.readAllBytes(resolvedFile), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String printableValue = ConfigKeys.shouldCensorValue(path) ? "*****" : value;
|
||||
this.plugin.getLogger().info(String.format("Resolved configuration value from file secret: %s = %s", key, printableValue));
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LuckPermsPlugin getPlugin() {
|
||||
return this.plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
+17
-14
@@ -46,9 +46,10 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Base implementation of {@link ContextManager} which caches content lookups.
|
||||
* Base implementation of {@link ContextManager}.
|
||||
*
|
||||
* @param <S> the calculator type
|
||||
* @param <S> the subject type
|
||||
* @param <P> the player type
|
||||
*/
|
||||
public abstract class ContextManager<S, P extends S> {
|
||||
|
||||
@@ -77,14 +78,10 @@ public abstract class ContextManager<S, P extends S> {
|
||||
|
||||
public abstract UUID getUniqueId(P player);
|
||||
|
||||
public abstract QueryOptionsSupplier getCacheFor(S subject);
|
||||
|
||||
public QueryOptions getQueryOptions(S subject) {
|
||||
return getCacheFor(subject).getQueryOptions();
|
||||
}
|
||||
public abstract QueryOptions getQueryOptions(S subject);
|
||||
|
||||
public ImmutableContextSet getContext(S subject) {
|
||||
return getCacheFor(subject).getContextSet();
|
||||
return getQueryOptions(subject).context();
|
||||
}
|
||||
|
||||
public QueryOptions getStaticQueryOptions() {
|
||||
@@ -95,11 +92,13 @@ public abstract class ContextManager<S, P extends S> {
|
||||
return getStaticQueryOptions().context();
|
||||
}
|
||||
|
||||
public QueryOptions formQueryOptions(ImmutableContextSet contextSet) {
|
||||
return this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder().context(contextSet).build();
|
||||
public void customizeStaticQueryOptions(QueryOptions.Builder builder) {
|
||||
// overridden
|
||||
}
|
||||
|
||||
public abstract QueryOptions formQueryOptions(S subject, ImmutableContextSet contextSet);
|
||||
public void customizeQueryOptions(S subject, QueryOptions.Builder builder) {
|
||||
// overridden
|
||||
}
|
||||
|
||||
public void signalContextUpdate(S subject) {
|
||||
if (subject == null) {
|
||||
@@ -113,7 +112,7 @@ public abstract class ContextManager<S, P extends S> {
|
||||
this.plugin.getEventDispatcher().dispatchContextUpdate(subject);
|
||||
}
|
||||
|
||||
protected abstract void invalidateCache(S subject);
|
||||
public abstract void invalidateCache(S subject);
|
||||
|
||||
public void registerCalculator(ContextCalculator<? super S> calculator) {
|
||||
String calculatorClass = calculator.getClass().getName();
|
||||
@@ -157,7 +156,9 @@ public abstract class ContextManager<S, P extends S> {
|
||||
callContextCalculator(calculator, subject, consumer);
|
||||
}
|
||||
|
||||
return formQueryOptions(subject, accumulator.build());
|
||||
QueryOptions.Builder builder = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder().context(accumulator.build());
|
||||
customizeQueryOptions(subject, builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private QueryOptions calculateStatic() {
|
||||
@@ -168,7 +169,9 @@ public abstract class ContextManager<S, P extends S> {
|
||||
callStaticContextCalculator(calculator, consumer);
|
||||
}
|
||||
|
||||
return formQueryOptions(accumulator.build());
|
||||
QueryOptions.Builder builder = this.plugin.getConfiguration().get(ConfigKeys.GLOBAL_QUERY_OPTIONS).toBuilder().context(accumulator.build());
|
||||
customizeStaticQueryOptions(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public ImmutableContextSet getPotentialContexts() {
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.context.manager;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ContextManager} which utilises 'detached' supplier caches stored alongside the subject instances.
|
||||
*/
|
||||
public abstract class DetachedContextManager<S, P extends S> extends ContextManager<S, P> {
|
||||
|
||||
private final LoadingCache<S, QueryOptions> fallbackContextsCache = CaffeineFactory.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(this::calculate);
|
||||
|
||||
protected DetachedContextManager(LuckPermsPlugin plugin, Class<S> subjectClass, Class<P> playerClass) {
|
||||
super(plugin, subjectClass, playerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions(S subject) {
|
||||
QueryOptionsSupplier supplier = getQueryOptionsSupplier(subject);
|
||||
if (supplier != null) {
|
||||
return supplier.getQueryOptions();
|
||||
}
|
||||
return this.fallbackContextsCache.get(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache(S subject) {
|
||||
QueryOptionsSupplier queryOptionsSupplier = getQueryOptionsSupplier(subject);
|
||||
if (queryOptionsSupplier != null) {
|
||||
queryOptionsSupplier.invalidateCache();
|
||||
}
|
||||
this.fallbackContextsCache.invalidate(subject);
|
||||
}
|
||||
|
||||
public QueryOptionsSupplier createQueryOptionsSupplier(S subject) {
|
||||
return new QueryOptionsCache<>(subject, this);
|
||||
}
|
||||
|
||||
public abstract @Nullable QueryOptionsSupplier getQueryOptionsSupplier(S subject);
|
||||
|
||||
}
|
||||
+7
-2
@@ -37,11 +37,11 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @param <T> the player type
|
||||
*/
|
||||
public final class QueryOptionsCache<T> extends ExpiringCache<QueryOptions> implements QueryOptionsSupplier {
|
||||
final class QueryOptionsCache<T> extends ExpiringCache<QueryOptions> implements QueryOptionsSupplier {
|
||||
private final T subject;
|
||||
private final ContextManager<T, ?> contextManager;
|
||||
|
||||
public QueryOptionsCache(T subject, ContextManager<T, ?> contextManager) {
|
||||
QueryOptionsCache(T subject, ContextManager<T, ?> contextManager) {
|
||||
super(50L, TimeUnit.MILLISECONDS); // expire roughly every tick
|
||||
this.subject = subject;
|
||||
this.contextManager = contextManager;
|
||||
@@ -61,4 +61,9 @@ public final class QueryOptionsCache<T> extends ExpiringCache<QueryOptions> impl
|
||||
public ImmutableContextSet getContextSet() {
|
||||
return get().context();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache() {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
+2
@@ -39,4 +39,6 @@ public interface QueryOptionsSupplier {
|
||||
return getQueryOptions().context();
|
||||
}
|
||||
|
||||
void invalidateCache();
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.context.manager;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public abstract class SimpleContextManager<S, P extends S> extends ContextManager<S, P> {
|
||||
|
||||
private final LoadingCache<S, QueryOptions> contextsCache = CaffeineFactory.newBuilder()
|
||||
.expireAfterWrite(50, TimeUnit.MILLISECONDS)
|
||||
.build(this::calculate);
|
||||
|
||||
protected SimpleContextManager(LuckPermsPlugin plugin, Class<S> subjectClass, Class<P> playerClass) {
|
||||
super(plugin, subjectClass, playerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions(S subject) {
|
||||
return this.contextsCache.get(subject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache(S subject) {
|
||||
this.contextsCache.invalidate(subject);
|
||||
}
|
||||
}
|
||||
@@ -62,28 +62,28 @@ public enum Dependency {
|
||||
ADVENTURE(
|
||||
"me{}lucko",
|
||||
"adventure-api",
|
||||
"4.13.0",
|
||||
"gcmYlY1KDrzbnE9nB8rA44oBZKPSMvv9kNRefoEuud0=",
|
||||
"4.21.1",
|
||||
"kQJlZ0gUxdTRRkskT43qiy2kpt9s654LvB0nqoCP6YE=",
|
||||
Relocation.of("adventure", "net{}kyori{}adventure")
|
||||
),
|
||||
ADVENTURE_PLATFORM(
|
||||
"me{}lucko",
|
||||
"adventure-platform-api",
|
||||
"4.13.0",
|
||||
"4.21.1",
|
||||
"Kk8IkEMVa9ITBfC3yocpcXQiZ9CwN9VxeWjKUD8I0n0=",
|
||||
Relocation.of("adventure", "net{}kyori{}adventure")
|
||||
),
|
||||
ADVENTURE_PLATFORM_BUKKIT(
|
||||
"me{}lucko",
|
||||
"adventure-platform-bukkit",
|
||||
"4.13.3",
|
||||
"ZXw7pf+a6tjGdB2WO1rB/KQ+ETLAH8kQFSu3El7jopY=",
|
||||
"4.21.1",
|
||||
"NffwBnfT/Mc6VpsmTcaXPvckv9T4vPJD83adt0C8vao=",
|
||||
Relocation.of("adventure", "net{}kyori{}adventure")
|
||||
),
|
||||
ADVENTURE_PLATFORM_BUNGEECORD(
|
||||
"me{}lucko",
|
||||
"adventure-platform-bungeecord",
|
||||
"4.13.3",
|
||||
"4.21.1",
|
||||
"7hnndD6dO6LZoRbtOBdn6OFK0y/T2PqNLHxCg6zaQlo=",
|
||||
Relocation.of("adventure", "net{}kyori{}adventure")
|
||||
),
|
||||
|
||||
+1
-1
@@ -138,7 +138,7 @@ public enum DependencyRepository {
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the the {@code dependency} to the {@code file}, ensuring the
|
||||
* Downloads the {@code dependency} to the {@code file}, ensuring the
|
||||
* downloaded bytes match the checksum.
|
||||
*
|
||||
* @param dependency the dependency to download
|
||||
|
||||
+39
-27
@@ -23,48 +23,60 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.bulkupdate.comparison;
|
||||
package me.lucko.luckperms.common.filter;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A method of comparing two strings
|
||||
*/
|
||||
public interface Comparison {
|
||||
public enum Comparison {
|
||||
|
||||
EQUAL("=="),
|
||||
NOT_EQUAL("!="),
|
||||
SIMILAR("~~"),
|
||||
NOT_SIMILAR("!~");
|
||||
|
||||
public static final String WILDCARD = "%";
|
||||
public static final String WILDCARD_ONE = "_";
|
||||
|
||||
private final String symbol;
|
||||
|
||||
Comparison(String symbol) {
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the symbol which represents this comparison
|
||||
*
|
||||
* @return the comparison symbol
|
||||
*/
|
||||
String getSymbol();
|
||||
public String getSymbol() {
|
||||
return this.symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link CompiledExpression} for the given expression
|
||||
*
|
||||
* @param expression the expression
|
||||
* @return the compiled expression
|
||||
*/
|
||||
CompiledExpression compile(String expression);
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the comparison operator in SQL form
|
||||
*/
|
||||
void appendSql(PreparedStatementBuilder builder);
|
||||
public static Comparison parse(String s) {
|
||||
for (Comparison t : values()) {
|
||||
if (t.getSymbol().equals(s)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of {@link Comparison} which is bound to an expression.
|
||||
*/
|
||||
interface CompiledExpression {
|
||||
public static Pattern compilePatternForLikeSyntax(String expression) {
|
||||
expression = expression.replace(".", "\\.");
|
||||
|
||||
/**
|
||||
* Tests the expression against a given string, according to the
|
||||
* rules of the parent {@link Comparison}.
|
||||
*
|
||||
* @param string the string
|
||||
* @return if there was a match
|
||||
*/
|
||||
boolean test(String string);
|
||||
// convert from SQL LIKE syntax to regex
|
||||
expression = expression.replace(WILDCARD_ONE, ".");
|
||||
expression = expression.replace(WILDCARD, ".*");
|
||||
|
||||
return Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
|
||||
}
|
||||
+19
-23
@@ -23,24 +23,28 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.bulkupdate.comparison;
|
||||
package me.lucko.luckperms.common.filter;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class Constraint {
|
||||
|
||||
public static Constraint of(Comparison comparison, String expression) {
|
||||
return new Constraint(comparison, expression);
|
||||
}
|
||||
public class Constraint<T> {
|
||||
|
||||
private final Comparison comparison;
|
||||
private final String expressionValue;
|
||||
private final Comparison.CompiledExpression compiledExpression;
|
||||
private final T value;
|
||||
private final Predicate<T> predicate;
|
||||
|
||||
private Constraint(Comparison comparison, String expression) {
|
||||
Constraint(Comparison comparison, T value, Predicate<T> predicate) {
|
||||
this.comparison = comparison;
|
||||
this.expressionValue = expression;
|
||||
this.compiledExpression = this.comparison.compile(this.expressionValue);
|
||||
this.value = value;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
public Comparison comparison() {
|
||||
return this.comparison;
|
||||
}
|
||||
|
||||
public T value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,20 +53,12 @@ public class Constraint {
|
||||
* @param value the value
|
||||
* @return true if satisfied
|
||||
*/
|
||||
public boolean eval(String value) {
|
||||
return this.compiledExpression.test(value);
|
||||
}
|
||||
|
||||
public void appendSql(PreparedStatementBuilder builder, String field) {
|
||||
// e.g. field LIKE ?
|
||||
builder.append(field).append(' ');
|
||||
this.comparison.appendSql(builder);
|
||||
builder.append(' ');
|
||||
builder.variable(this.expressionValue);
|
||||
public boolean evaluate(T value) {
|
||||
return this.predicate.test(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.comparison + " " + this.expressionValue;
|
||||
return this.comparison + " " + this.value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.filter;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public interface ConstraintFactory<T> {
|
||||
|
||||
Predicate<T> equal(T value);
|
||||
Predicate<T> notEqual(T value);
|
||||
Predicate<T> similar(T value);
|
||||
Predicate<T> notSimilar(T value);
|
||||
|
||||
default Constraint<T> build(Comparison comparison, T value) {
|
||||
switch (comparison) {
|
||||
case EQUAL:
|
||||
return new Constraint<>(comparison, value, equal(value));
|
||||
case NOT_EQUAL:
|
||||
return new Constraint<>(comparison, value, notEqual(value));
|
||||
case SIMILAR:
|
||||
return new Constraint<>(comparison, value, similar(value));
|
||||
case NOT_SIMILAR:
|
||||
return new Constraint<>(comparison, value, notSimilar(value));
|
||||
default:
|
||||
throw new AssertionError(comparison);
|
||||
}
|
||||
}
|
||||
|
||||
ConstraintFactory<String> STRINGS = new ConstraintFactory<String>() {
|
||||
@Override
|
||||
public Predicate<String> equal(String value) {
|
||||
return value::equalsIgnoreCase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<String> notEqual(String value) {
|
||||
return string -> !value.equalsIgnoreCase(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<String> similar(String value) {
|
||||
Pattern pattern = Comparison.compilePatternForLikeSyntax(value);
|
||||
return string -> pattern.matcher(string).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<String> notSimilar(String value) {
|
||||
Pattern pattern = Comparison.compilePatternForLikeSyntax(value);
|
||||
return string -> !pattern.matcher(string).matches();
|
||||
}
|
||||
};
|
||||
|
||||
ConstraintFactory<UUID> UUIDS = new ConstraintFactory<UUID>() {
|
||||
@Override
|
||||
public Predicate<UUID> equal(UUID value) {
|
||||
return value::equals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<UUID> notEqual(UUID value) {
|
||||
return string -> !value.equals(string);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<UUID> similar(UUID value) {
|
||||
Pattern pattern = Comparison.compilePatternForLikeSyntax(value.toString());
|
||||
return uuid -> pattern.matcher(uuid.toString()).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<UUID> notSimilar(UUID value) {
|
||||
Pattern pattern = Comparison.compilePatternForLikeSyntax(value.toString());
|
||||
return uuid -> !pattern.matcher(uuid.toString()).matches();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.filter;
|
||||
|
||||
public class Filter<T, FT> {
|
||||
private final FilterField<T, FT> field;
|
||||
private final Constraint<FT> constraint;
|
||||
|
||||
public Filter(FilterField<T, FT> field, Constraint<FT> constraint) {
|
||||
this.field = field;
|
||||
this.constraint = constraint;
|
||||
}
|
||||
|
||||
public final FilterField<T, FT> field() {
|
||||
return this.field;
|
||||
}
|
||||
|
||||
public final Constraint<FT> constraint() {
|
||||
return this.constraint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the given value satisfies this filter
|
||||
*
|
||||
* @param value the value
|
||||
* @return true if satisfied
|
||||
*/
|
||||
public boolean evaluate(T value) {
|
||||
return this.constraint.evaluate(this.field.getValue(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.field + " " + this.constraint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.filter;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Represents a field that can be filtered on.
|
||||
*
|
||||
* @param <T> the type the field is on
|
||||
*/
|
||||
public interface FilterField<T, FT> {
|
||||
|
||||
static <T, FT> FilterField<T, FT> named(String name, Function<T, FT> func) {
|
||||
return new FilterField<T, FT>() {
|
||||
@Override
|
||||
public FT getValue(T object) {
|
||||
return func.apply(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of this field on the given object.
|
||||
*
|
||||
* @param object the object
|
||||
* @return the field value as a string
|
||||
*/
|
||||
FT getValue(T object);
|
||||
|
||||
default Filter<T, FT> isEqualTo(FT value, ConstraintFactory<FT> factory) {
|
||||
return new Filter<>(this, factory.build(Comparison.EQUAL, value));
|
||||
}
|
||||
|
||||
default Filter<T, FT> isNotEqualTo(FT value, ConstraintFactory<FT> factory) {
|
||||
return new Filter<>(this, factory.build(Comparison.NOT_EQUAL, value));
|
||||
}
|
||||
|
||||
default Filter<T, FT> isSimilarTo(FT value, ConstraintFactory<FT> factory) {
|
||||
return new Filter<>(this, factory.build(Comparison.SIMILAR, value));
|
||||
}
|
||||
|
||||
default Filter<T, FT> isNotSimilarTo(FT value, ConstraintFactory<FT> factory) {
|
||||
return new Filter<>(this, factory.build(Comparison.NOT_SIMILAR, value));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.filter;
|
||||
|
||||
import com.google.common.collect.ForwardingList;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FilterList<T> extends ForwardingList<Filter<T, ?>> {
|
||||
|
||||
public static <T> FilterList<T> empty() {
|
||||
return new FilterList<>(LogicalOperator.AND, ImmutableList.of());
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> FilterList<T> and(Filter<T, ?>... filters) {
|
||||
return new FilterList<>(LogicalOperator.AND, ImmutableList.copyOf(filters));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> FilterList<T> or(Filter<T, ?>... filters) {
|
||||
return new FilterList<>(LogicalOperator.OR, ImmutableList.copyOf(filters));
|
||||
}
|
||||
|
||||
private final LogicalOperator operator;
|
||||
private final List<Filter<T, ?>> filters;
|
||||
|
||||
public FilterList(LogicalOperator operator, List<Filter<T, ?>> filters) {
|
||||
this.operator = operator;
|
||||
this.filters = filters;
|
||||
}
|
||||
|
||||
public LogicalOperator operator() {
|
||||
return this.operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Filter<T, ?>> delegate() {
|
||||
return this.filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a value satisfies all (AND) or any (OR) filters in the list
|
||||
*
|
||||
* @param value the value to check
|
||||
* @return true if satisfied
|
||||
*/
|
||||
public boolean evaluate(T value) {
|
||||
return this.operator.match(this.filters, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String operator = this.operator.name().toLowerCase(Locale.ROOT);
|
||||
return this.filters.stream().map(Filter::toString).collect(Collectors.joining(" " + operator + " "));
|
||||
}
|
||||
|
||||
public enum LogicalOperator {
|
||||
AND {
|
||||
@Override
|
||||
public <T> boolean match(List<? extends Filter<T, ?>> filters, T value) {
|
||||
return filters.stream().allMatch(filter -> filter.evaluate(value)); // true if empty
|
||||
}
|
||||
},
|
||||
OR {
|
||||
@Override
|
||||
public <T> boolean match(List<? extends Filter<T, ?>> filters, T value) {
|
||||
return filters.stream().anyMatch(filter -> filter.evaluate(value)); // false if empty
|
||||
}
|
||||
};
|
||||
|
||||
public abstract <T> boolean match(List<? extends Filter<T, ?>> filters, T value);
|
||||
}
|
||||
|
||||
}
|
||||
Loaded 100 of 294 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user