Compare commits

31 Commits

Author SHA1 Message Date
404f221ccf added Logging for InteractionChecks
Some checks failed
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 33s
Test / Gradle-Test (push) Failing after 40s
2024-12-19 21:07:42 +01:00
7249c99b69 add Logging to Parsers 2024-12-19 20:38:04 +01:00
b764972eba make use of new helper method in InteractionMethod 2024-12-19 20:15:22 +01:00
83ee4b1efa add method name helper method 2024-12-19 20:04:53 +01:00
6b86e9ff87 add initialization Logging 2024-12-19 19:41:49 +01:00
7a40aebd6d add Interactionmethod logging 2024-12-19 19:41:37 +01:00
76ab779ab2 fix position of Logging in InteractionRegistry
All checks were successful
github-mirror / push-github (push) Successful in 5s
Build / Gradle-Build (push) Successful in 35s
Test / Gradle-Test (push) Successful in 47s
2024-12-19 18:36:51 +01:00
3d19fae6b8 fix null issue in InteractionRegistry
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 33s
Test / Gradle-Test (push) Successful in 44s
2024-12-19 18:34:00 +01:00
1ecbc563a6 add Logging in InteractionRegistry
Some checks failed
github-mirror / push-github (push) Successful in 5s
Build / Gradle-Build (push) Successful in 34s
Test / Gradle-Test (push) Failing after 44s
2024-12-19 18:07:33 +01:00
bf0022775d add helper LoggerUtil method 2024-12-19 13:30:36 +01:00
a17f5e826f add LoggerUtil to decide which Logger to get
All checks were successful
github-mirror / push-github (push) Successful in 5s
Build / Gradle-Build (push) Successful in 35s
Test / Gradle-Test (push) Successful in 39s
2024-12-19 12:28:45 +01:00
3de0f32074 change to just javacord api dependency 2024-12-19 12:28:27 +01:00
d8504a7cde Merge pull request 'add Checks system' (#6) from feat/checks into dev
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 11s
Publish / Gradle-Publish (push) Successful in 11s
Test / Gradle-Test (push) Successful in 16s
Reviewed-on: #6
2024-12-05 07:51:36 +00:00
bef34ee548 fix null issue
All checks were successful
github-mirror / push-github (push) Successful in 3s
Build / Gradle-Build (push) Successful in 12s
Test / Gradle-Test (push) Successful in 16s
2024-12-03 20:20:57 +01:00
29bb7e667e add PermissionCHeck test
Some checks failed
github-mirror / push-github (push) Successful in 5s
Build / Gradle-Build (push) Successful in 11s
Test / Gradle-Test (push) Failing after 16s
2024-12-02 21:21:00 +01:00
94da2a0e3c change logic to always give objects the highest value 2024-12-02 21:20:49 +01:00
7f47130461 add missing annotation annotations 2024-12-02 21:20:26 +01:00
83a3efd4b8 add canRun check which i forgor 2024-12-02 21:19:58 +01:00
aefd8a51a0 change wrong annotation class usage 2024-12-02 21:19:42 +01:00
4332592dfa add Javacord PermissionCheck
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 12s
Test / Gradle-Test (push) Successful in 17s
2024-12-02 13:16:28 +01:00
c363ab9744 add ability to return false to cancel execution in pre Checks and remove return type on post checks
All checks were successful
github-mirror / push-github (push) Successful in 7s
Build / Gradle-Build (push) Successful in 14s
Test / Gradle-Test (push) Successful in 21s
2024-12-01 13:06:42 +01:00
33392b02fb add InteractionCheck test
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 13s
Test / Gradle-Test (push) Successful in 15s
2024-11-29 21:41:46 +01:00
b7333c2e5e fix problem with multiple method overrides in generic types. 2024-11-29 21:41:18 +01:00
239e921e6f change Annotation#getClass to Annotation#annotationType because it was not working as expected 2024-11-29 21:37:13 +01:00
6eb7fb723f add geantyref to fix and simplify generic Type parsing.
Also switch to java 23 to avoid conflicts and issues.
2024-11-29 21:36:02 +01:00
659218682e add context Object to check methods and create the ability to have a specific method for each type of context or one for all by using the superclass and casting yourself
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 12s
Test / Gradle-Test (push) Successful in 17s
2024-11-29 18:17:33 +01:00
019ba8f552 add getMostSpecificMethod method to simplify Check method parsing.
This Method searches the The method that has the best matching parameters with the fewest inheritance levels as possible. Left sided priority
2024-11-29 18:15:47 +01:00
f89ae5e425 - add prototype Interactioncheck impementation.
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 12s
Test / Gradle-Test (push) Successful in 16s
- refactor dependency injection to have all widely used dependencies in the Marinara class.
2024-11-28 10:32:48 +01:00
582e0f0bae implement AnnotationParser system
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 13s
Test / Gradle-Test (push) Successful in 16s
2024-11-24 00:02:19 +01:00
0ea330d48b move to seperate files because gitea does not have expressions yet
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 9s
Publish / Gradle-Publish (push) Successful in 10s
Test / Gradle-Test (push) Successful in 13s
2024-11-20 12:01:47 +01:00
c241f6b1fe enable dev branch publishing
All checks were successful
github-mirror / push-github (push) Successful in 4s
Build / Gradle-Build (push) Successful in 17s
Publish / Gradle-Publish (push) Successful in 6s
Test / Gradle-Test (push) Successful in 13s
2024-11-20 11:52:41 +01:00
28 changed files with 719 additions and 98 deletions

View File

@@ -0,0 +1,40 @@
name: Publish
on:
push:
branches: [dev]
jobs:
Gradle-Publish:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '23'
check-latest: true
distribution: 'zulu'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
add-job-summary: always
cache-cleanup: on-success
- name: Cache Gradle dependencies
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Publish Dev
env:
GITEA_TOKEN: ${{ secrets.PUBLISH_PACKAGE_TOKEN }}
run: chmod +x gradlew; ./gradlew publishAllPublicationsToGiteaRepository

View File

@@ -1,11 +1,11 @@
name: Test name: Publish
on: on:
push: push:
branches: [master] branches: [master]
jobs: jobs:
Gradle-Test: Gradle-Publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -34,7 +34,7 @@ jobs:
restore-keys: | restore-keys: |
${{ runner.os }}-gradle- ${{ runner.os }}-gradle-
- name: Publish - name: Publish Release
env: env:
GITEA_TOKEN: ${{ secrets.PUBLISH_PACKAGE_TOKEN }} GITEA_TOKEN: ${{ secrets.PUBLISH_PACKAGE_TOKEN }}
run: chmod +x gradlew; ./gradlew publishAllPublicationsToGiteaRepository run: chmod +x gradlew; ./gradlew publishAllPublicationsToGiteaRepository -Prelease

View File

@@ -8,6 +8,7 @@ allprojects {
group = "net.tomatentum.Marinara" group = "net.tomatentum.Marinara"
version = "1.0.0-RC1" + (if (!project.hasProperty("release")) ("-" + getGitHash()) else "") version = "1.0.0-RC1" + (if (!project.hasProperty("release")) ("-" + getGitHash()) else "")
description = "A simple but powerful, library-agnostic Discord Interaction Wrapper." description = "A simple but powerful, library-agnostic Discord Interaction Wrapper."
} }
subprojects { subprojects {
@@ -18,6 +19,8 @@ subprojects {
publishing { publishing {
publications { publications {
create<MavenPublication>("maven") { create<MavenPublication>("maven") {
if (!project.hasProperty("release"))
artifactId = project.getName() + "-dev"
from(components["java"]) from(components["java"])
} }
} }

View File

@@ -9,6 +9,6 @@ geantyref = "2.0.0"
[libraries] [libraries]
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" } junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
log4j = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j"} log4j = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j"}
javacord = { module = "org.javacord:javacord", version.ref = "javacord"} javacord = { module = "org.javacord:javacord", version.ref = "javacord"}
geantyref = { module = "io.leangen.geantyref:geantyref", version.ref = "geantyref"} geantyref = { module = "io.leangen.geantyref:geantyref", version.ref = "geantyref"}

View File

@@ -21,13 +21,13 @@ dependencies {
testRuntimeOnly("org.junit.platform:junit-platform-launcher") testRuntimeOnly("org.junit.platform:junit-platform-launcher")
implementation(libs.log4j) implementation(libs.log4j)
implementation(libs.geantyref)
} }
// Apply a specific Java toolchain to ease working on different environments. // Apply a specific Java toolchain to ease working on different environments.
java { java {
toolchain { toolchain {
languageVersion = JavaLanguageVersion.of(21) languageVersion = JavaLanguageVersion.of(23)
} }
} }

View File

@@ -1,22 +1,40 @@
package net.tomatentum.marinara; package net.tomatentum.marinara;
import org.apache.logging.log4j.Logger;
import net.tomatentum.marinara.registry.InteractionCheckRegistry;
import net.tomatentum.marinara.registry.InteractionRegistry; import net.tomatentum.marinara.registry.InteractionRegistry;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.wrapper.LibraryWrapper; import net.tomatentum.marinara.wrapper.LibraryWrapper;
public class Marinara { public class Marinara {
private Logger logger = LoggerUtil.getLogger(getClass());
public static <T extends LibraryWrapper> Marinara load(LibraryWrapper wrapper) { public static <T extends LibraryWrapper> Marinara load(LibraryWrapper wrapper) {
InteractionRegistry registry = new InteractionRegistry(wrapper); return new Marinara(wrapper);
return new Marinara(registry);
} }
private InteractionRegistry registry; private InteractionRegistry registry;
private InteractionCheckRegistry checkRegistry;
private LibraryWrapper wrapper;
private Marinara(InteractionRegistry registry) { private Marinara(LibraryWrapper wrapper) {
this.registry = registry; this.wrapper = wrapper;
this.registry = new InteractionRegistry(this);
this.checkRegistry = new InteractionCheckRegistry();
logger.info("Marinara loaded successfully!");
} }
public InteractionRegistry getRegistry() { public InteractionRegistry getRegistry() {
return registry; return registry;
} }
public InteractionCheckRegistry getCheckRegistry() {
return checkRegistry;
}
public LibraryWrapper getWrapper() {
return wrapper;
}
} }

View File

@@ -0,0 +1,48 @@
package net.tomatentum.marinara.checks;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.apache.logging.log4j.Logger;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.util.ReflectionUtil;
public record AppliedCheck(InteractionCheck<?> check, Annotation annotation) {
private static Logger logger = LoggerUtil.getLogger(AppliedCheck.class);
public boolean pre(Object context) {
Method[] methods = Arrays.stream(check.getClass().getMethods())
.filter(x -> x.getName().equals("preExec"))
.filter(x -> !x.isBridge())
.toArray(s -> new Method[s]);
Method method = ReflectionUtil.getMostSpecificMethod(methods, context.getClass(), annotation.annotationType());
method.setAccessible(true);
try {
logger.debug("Executing pre check {} with context {}", check.getClass().getName(), context.toString());
return (boolean) method.invoke(check, context, annotation);
} catch (IllegalAccessException | InvocationTargetException | SecurityException e) {
logger.fatal(e);
return false;
}
}
public void post(Object context) {
Method[] methods = Arrays.stream(check.getClass().getMethods())
.filter(x -> x.getName().equals("postExec"))
.filter(x -> !x.isBridge())
.toArray(s -> new Method[s]);
Method method = ReflectionUtil.getMostSpecificMethod(methods, context.getClass(), annotation.annotationType());
method.setAccessible(true);
try {
logger.debug("Executing pre check {} with context {}", check.getClass().getName(), context.toString());
method.invoke(check, context, annotation);
} catch (IllegalAccessException | InvocationTargetException | SecurityException e) {
logger.fatal(e);
}
}
}

View File

@@ -0,0 +1,10 @@
package net.tomatentum.marinara.checks;
import java.lang.annotation.Annotation;
public interface InteractionCheck<A extends Annotation> {
public boolean preExec(Object context, A annotation);
public void postExec(Object context, A annotation);
}

View File

@@ -16,9 +16,18 @@ public record ExecutableSlashCommandDefinition(
if (!(o instanceof ExecutableSlashCommandDefinition)) if (!(o instanceof ExecutableSlashCommandDefinition))
return false; return false;
ExecutableSlashCommandDefinition other = (ExecutableSlashCommandDefinition) o; ExecutableSlashCommandDefinition other = (ExecutableSlashCommandDefinition) o;
return other.applicationCommand.name().equals(this.applicationCommand.name()) && boolean equals = false;
other.subCommandGroup.name().equals(this.subCommandGroup.name()) &&
other.subCommand.name().equals(this.subCommand.name()); if (this.applicationCommand() != null && other.subCommandGroup() != null)
equals = this.applicationCommand.name().equals(other.applicationCommand().name());
if (this.subCommandGroup() != null && other.subCommandGroup() != null)
equals = this.subCommandGroup().name().equals(other.subCommandGroup().name());
if (this.subCommand() != null && other.subCommand() != null)
equals = this.subCommand().name().equals(other.subCommand().name());
return equals;
} }
@Override @Override

View File

@@ -2,39 +2,40 @@ package net.tomatentum.marinara.interaction.methods;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import net.tomatentum.marinara.Marinara;
import net.tomatentum.marinara.interaction.InteractionHandler; import net.tomatentum.marinara.interaction.InteractionHandler;
import net.tomatentum.marinara.interaction.InteractionType; import net.tomatentum.marinara.interaction.InteractionType;
import net.tomatentum.marinara.interaction.annotation.Button; import net.tomatentum.marinara.parser.AnnotationParser;
import net.tomatentum.marinara.wrapper.LibraryWrapper; import net.tomatentum.marinara.parser.ButtonParser;
public class ButtonInteractionMethod extends InteractionMethod { public class ButtonInteractionMethod extends InteractionMethod {
private String customId; private String customId;
ButtonInteractionMethod(Method method, InteractionHandler handler, LibraryWrapper wrapper) { ButtonInteractionMethod(Method method, InteractionHandler handler, Marinara marinara) {
super(method, handler, wrapper); super(method, handler, marinara);
parseMethod(); }
@Override
public AnnotationParser[] getParsers() {
return new AnnotationParser[] {
new ButtonParser(method, (x) -> { this.customId = x; } )
};
} }
@Override @Override
public Object getParameter(Object parameter, int index) { public Object getParameter(Object parameter, int index) {
Class<?> type = getMethod().getParameterTypes()[index+1]; Class<?> type = getMethod().getParameterTypes()[index+1];
return wrapper.getComponentContextObject(parameter, type); return marinara.getWrapper().getComponentContextObject(parameter, type);
} }
@Override @Override
public boolean canRun(Object context) { public boolean canRun(Object context) {
return wrapper.getButtonId(context).equals(customId); return marinara.getWrapper().getButtonId(context).equals(customId);
} }
@Override @Override
public InteractionType getType() { public InteractionType getType() {
return InteractionType.BUTTON; return InteractionType.BUTTON;
} }
private void parseMethod() {
Button button = getMethod().getAnnotation(Button.class);
this.customId = button.value();
}
} }

View File

@@ -7,35 +7,58 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.Logger;
import net.tomatentum.marinara.Marinara;
import net.tomatentum.marinara.checks.AppliedCheck;
import net.tomatentum.marinara.interaction.InteractionHandler; import net.tomatentum.marinara.interaction.InteractionHandler;
import net.tomatentum.marinara.interaction.InteractionType; import net.tomatentum.marinara.interaction.InteractionType;
import net.tomatentum.marinara.interaction.annotation.Button; import net.tomatentum.marinara.interaction.annotation.Button;
import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; import net.tomatentum.marinara.interaction.commands.annotation.SubCommand;
import net.tomatentum.marinara.wrapper.LibraryWrapper; import net.tomatentum.marinara.parser.AnnotationParser;
import net.tomatentum.marinara.parser.InteractionCheckParser;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.util.ReflectionUtil;
public abstract class InteractionMethod { public abstract class InteractionMethod {
public static InteractionMethod create(Method method, InteractionHandler handler, LibraryWrapper wrapper) { public static InteractionMethod create(Method method, InteractionHandler handler, Marinara marinara) {
if (method.isAnnotationPresent(SlashCommand.class) || method.isAnnotationPresent(SubCommand.class)) if (method.isAnnotationPresent(SlashCommand.class) || method.isAnnotationPresent(SubCommand.class))
return new SlashCommandInteractionMethod(method, handler, wrapper); return new SlashCommandInteractionMethod(method, handler, marinara);
if (method.isAnnotationPresent(Button.class)) if (method.isAnnotationPresent(Button.class))
return new ButtonInteractionMethod(method, handler, wrapper); return new ButtonInteractionMethod(method, handler, marinara);
return null; return null;
} }
protected Method method; protected Method method;
protected InteractionHandler handler; protected InteractionHandler handler;
protected LibraryWrapper wrapper; protected Marinara marinara;
protected List<AnnotationParser> parsers;
protected List<AppliedCheck> appliedChecks;
protected InteractionMethod(Method method, InteractionHandler handler, LibraryWrapper wrapper) { private Logger logger = LoggerUtil.getLogger(getClass());
protected InteractionMethod(Method method,
InteractionHandler handler,
Marinara marinara
) {
if (!Arrays.asList(handler.getClass().getMethods()).contains(method)) if (!Arrays.asList(handler.getClass().getMethods()).contains(method))
throw new InvalidParameterException("Method does not apply to specified handler"); throw new InvalidParameterException("Method does not apply to specified handler");
this.method = method; this.method = method;
this.handler = handler; this.handler = handler;
this.wrapper = wrapper; this.marinara = marinara;
this.parsers = new ArrayList<>(Arrays.asList(getParsers()));
this.appliedChecks = new ArrayList<>();
parsers.add(new InteractionCheckParser(method, appliedChecks::add, marinara.getCheckRegistry()));
parsers.stream().forEach(AnnotationParser::parse);
} }
public abstract AnnotationParser[] getParsers();
public abstract Object getParameter(Object parameter, int index); public abstract Object getParameter(Object parameter, int index);
public abstract boolean canRun(Object context); public abstract boolean canRun(Object context);
@@ -43,26 +66,38 @@ public abstract class InteractionMethod {
public abstract InteractionType getType(); public abstract InteractionType getType();
public void run(Object context) { public void run(Object context) {
int parameterCount = method.getParameterCount(); if (this.appliedChecks.stream().filter(x -> !x.pre(context)).count() > 0)
List<Object> parameters = new ArrayList<>(); return;
for (int i = 0; i < parameterCount; i++) {
if (i == 0) {
parameters.add(context);
continue;
}
parameters.add(getParameter(context, i-1));
}
method.setAccessible(true); method.setAccessible(true);
try { try {
method.invoke(handler, parameters.toArray()); method.invoke(handler, getParameters(context));
}catch (IllegalAccessException | InvocationTargetException ex) { }catch (IllegalAccessException | InvocationTargetException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
this.appliedChecks.forEach(x -> x.post(context));
} }
public Method getMethod() { public Method getMethod() {
return method; return method;
} }
private Object[] getParameters(Object context) {
int parameterCount = method.getParameterCount();
List<Object> parameters = new ArrayList<>();
for (int i = 0; i < parameterCount; i++) {
Object parameter;
if (i == 0) {
parameter = context;
}else
parameter = getParameter(context, i-1);
logger.trace("Found parameter {}={} for method {}", parameter.getClass().toString(), parameter, ReflectionUtil.getFullMethodName(method));
parameters.add(parameter);
}
return parameters.toArray();
}
} }

View File

@@ -2,32 +2,36 @@ package net.tomatentum.marinara.interaction.methods;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import net.tomatentum.marinara.Marinara;
import net.tomatentum.marinara.interaction.InteractionHandler; import net.tomatentum.marinara.interaction.InteractionHandler;
import net.tomatentum.marinara.interaction.InteractionType; import net.tomatentum.marinara.interaction.InteractionType;
import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition;
import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; import net.tomatentum.marinara.parser.AnnotationParser;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; import net.tomatentum.marinara.parser.SlashCommandParser;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommandGroup;
import net.tomatentum.marinara.util.ReflectionUtil;
import net.tomatentum.marinara.wrapper.LibraryWrapper;
public class SlashCommandInteractionMethod extends InteractionMethod { public class SlashCommandInteractionMethod extends InteractionMethod {
private ExecutableSlashCommandDefinition commandDefinition; private ExecutableSlashCommandDefinition commandDefinition;
SlashCommandInteractionMethod(Method method, InteractionHandler handler, LibraryWrapper wrapper) { SlashCommandInteractionMethod(Method method, InteractionHandler handler, Marinara marinara) {
super(method, handler, wrapper); super(method, handler, marinara);
parseMethod(); }
@Override
public AnnotationParser[] getParsers() {
return new AnnotationParser[] {
new SlashCommandParser(method, (x) -> { this.commandDefinition = x; } )
};
} }
@Override @Override
public Object getParameter(Object context, int index) { public Object getParameter(Object context, int index) {
return wrapper.convertCommandOption(context, commandDefinition.options()[index].type(), commandDefinition.options()[index].name()); return marinara.getWrapper().convertCommandOption(context, commandDefinition.options()[index].type(), commandDefinition.options()[index].name());
} }
@Override @Override
public boolean canRun(Object context) { public boolean canRun(Object context) {
ExecutableSlashCommandDefinition other = wrapper.getCommandDefinition(context); ExecutableSlashCommandDefinition other = marinara.getWrapper().getCommandDefinition(context);
return commandDefinition.equals(other); return commandDefinition.equals(other);
} }
@@ -40,24 +44,8 @@ public class SlashCommandInteractionMethod extends InteractionMethod {
return commandDefinition; return commandDefinition;
} }
private void parseMethod() { public void setCommandDefinition(ExecutableSlashCommandDefinition commandDefinition) {
ReflectionUtil.checkValidCommandMethod(method); this.commandDefinition = commandDefinition;
SlashCommand cmd = ReflectionUtil.getAnnotation(method, SlashCommand.class);
ExecutableSlashCommandDefinition.Builder builder = new ExecutableSlashCommandDefinition.Builder();
builder.setApplicationCommand(cmd);
if (ReflectionUtil.isAnnotationPresent(method, SubCommandGroup.class)) {
SubCommandGroup cmdGroup = ReflectionUtil.getAnnotation(method, SubCommandGroup.class);
builder.setSubCommandGroup(cmdGroup);
}
if (ReflectionUtil.isAnnotationPresent(method, SubCommand.class)) {
SubCommand subCmd = ReflectionUtil.getAnnotation(method, SubCommand.class);
builder.setSubCommand(subCmd);
}
this.commandDefinition = builder.build();
} }
} }

View File

@@ -0,0 +1,8 @@
package net.tomatentum.marinara.parser;
import java.lang.reflect.Method;
public interface AnnotationParser {
void parse();
Method getMethod();
}

View File

@@ -0,0 +1,36 @@
package net.tomatentum.marinara.parser;
import java.lang.reflect.Method;
import java.util.function.Consumer;
import org.apache.logging.log4j.Logger;
import net.tomatentum.marinara.interaction.annotation.Button;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.util.ReflectionUtil;
public class ButtonParser implements AnnotationParser {
private Method method;
private Consumer<String> consumer;
private Logger logger = LoggerUtil.getLogger(getClass());
public ButtonParser(Method method, Consumer<String> consumer) {
this.method = method;
this.consumer = consumer;
}
@Override
public void parse() {
Button button = getMethod().getAnnotation(Button.class);
logger.trace("Parsed Button annotation {} for method {}", button.toString(), ReflectionUtil.getFullMethodName(method));
this.consumer.accept(button.value());
}
@Override
public Method getMethod() {
return this.method;
}
}

View File

@@ -0,0 +1,51 @@
package net.tomatentum.marinara.parser;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;
import java.util.function.Consumer;
import org.apache.logging.log4j.Logger;
import net.tomatentum.marinara.checks.AppliedCheck;
import net.tomatentum.marinara.checks.InteractionCheck;
import net.tomatentum.marinara.registry.InteractionCheckRegistry;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.util.ReflectionUtil;
public class InteractionCheckParser implements AnnotationParser {
private InteractionCheckRegistry checkRegistry;
private Method method;
private Consumer<AppliedCheck> consumer;
private Logger logger = LoggerUtil.getLogger(getClass());
public InteractionCheckParser(Method method, Consumer<AppliedCheck> consumer, InteractionCheckRegistry checkRegistry) {
this.checkRegistry = checkRegistry;
this.method = method;
this.consumer = consumer;
}
@Override
public void parse() {
Annotation[] annotations = method.getAnnotations();
Arrays.stream(annotations).forEach(this::convertAnnotation);
}
private void convertAnnotation(Annotation annotation) {
Optional<InteractionCheck<?>> check = this.checkRegistry.getCheckFromAnnotation(annotation.annotationType());
if (check.isPresent()) {
AppliedCheck appliedCheck = new AppliedCheck(check.get(), annotation);
logger.trace("Parsed InteractionCheck {} for annotation {} for method {}", check.getClass().getName(), annotation.toString(), ReflectionUtil.getFullMethodName(method));
consumer.accept(appliedCheck);
}
}
@Override
public Method getMethod() {
return this.method;
}
}

View File

@@ -0,0 +1,71 @@
package net.tomatentum.marinara.parser;
import java.lang.reflect.Method;
import java.util.function.Consumer;
import org.apache.logging.log4j.Logger;
import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition;
import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommand;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommandGroup;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.util.ReflectionUtil;
public class SlashCommandParser implements AnnotationParser {
private Method method;
private Consumer<ExecutableSlashCommandDefinition> consumer;
private Logger logger = LoggerUtil.getLogger(getClass());
public SlashCommandParser(Method method, Consumer<ExecutableSlashCommandDefinition> consumer) {
this.method = method;
this.consumer = consumer;
}
@Override
public void parse() {
this.checkValidCommandMethod(method);
SlashCommand cmd = ReflectionUtil.getAnnotation(method, SlashCommand.class);
ExecutableSlashCommandDefinition.Builder builder = new ExecutableSlashCommandDefinition.Builder();
builder.setApplicationCommand(cmd);
if (ReflectionUtil.isAnnotationPresent(method, SubCommandGroup.class)) {
SubCommandGroup cmdGroup = ReflectionUtil.getAnnotation(method, SubCommandGroup.class);
builder.setSubCommandGroup(cmdGroup);
}
if (ReflectionUtil.isAnnotationPresent(method, SubCommand.class)) {
SubCommand subCmd = ReflectionUtil.getAnnotation(method, SubCommand.class);
builder.setSubCommand(subCmd);
}
ExecutableSlashCommandDefinition def = builder.build();
logger.trace("Parsed using SlashCommandParser for method {} with the result:\n{}", ReflectionUtil.getFullMethodName(method), def.toString());
consumer.accept(builder.build());
}
@Override
public Method getMethod() {
return this.method;
}
private void checkValidCommandMethod(Method method) {
if (method.isAnnotationPresent(SlashCommand.class) &&
method.getDeclaringClass().isAnnotationPresent(SlashCommand.class)) {
throw new RuntimeException(method.getName() + ": Can't have ApplicationCommand Annotation on Class and Method");
}
if (!ReflectionUtil.isAnnotationPresent(method, SlashCommand.class))
throw new RuntimeException(method.getName() + ": Missing ApplicationCommand Annotation on either Class or Method");
if ((method.isAnnotationPresent(SubCommand.class) &&
!ReflectionUtil.isAnnotationPresent(method, SlashCommand.class))) {
throw new RuntimeException(method.getName() + ": Missing ApplicationCommand Annotation on either Method or Class");
}
}
}

View File

@@ -0,0 +1,40 @@
package net.tomatentum.marinara.registry;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.apache.logging.log4j.Logger;
import io.leangen.geantyref.GenericTypeReflector;
import net.tomatentum.marinara.checks.InteractionCheck;
import net.tomatentum.marinara.util.LoggerUtil;
public class InteractionCheckRegistry {
private List<InteractionCheck<?>> checks;
private Logger logger = LoggerUtil.getLogger(getClass());
public InteractionCheckRegistry() {
this.checks = new ArrayList<>();
}
public void addCheck(InteractionCheck<?> check) {
checks.add(check);
logger.info("Registered Check {}", check.getClass().getName());
}
public Optional<InteractionCheck<?>> getCheckFromAnnotation(Type annotation) {
for (InteractionCheck<?> interactionCheck : checks) {
ParameterizedType type = (ParameterizedType) GenericTypeReflector.getExactSuperType(interactionCheck.getClass(), InteractionCheck.class);
Type typeParam = type.getActualTypeArguments()[0];
if (typeParam.equals(annotation))
return Optional.of(interactionCheck);
}
return Optional.empty();
}
}

View File

@@ -5,30 +5,37 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import org.apache.logging.log4j.Logger;
import net.tomatentum.marinara.Marinara;
import net.tomatentum.marinara.interaction.InteractionHandler; import net.tomatentum.marinara.interaction.InteractionHandler;
import net.tomatentum.marinara.interaction.InteractionType; import net.tomatentum.marinara.interaction.InteractionType;
import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition; import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition;
import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition; import net.tomatentum.marinara.interaction.commands.ExecutableSlashCommandDefinition;
import net.tomatentum.marinara.interaction.methods.SlashCommandInteractionMethod; import net.tomatentum.marinara.interaction.methods.SlashCommandInteractionMethod;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.interaction.methods.InteractionMethod; import net.tomatentum.marinara.interaction.methods.InteractionMethod;
import net.tomatentum.marinara.wrapper.LibraryWrapper;
public class InteractionRegistry { public class InteractionRegistry {
private Logger logger = LoggerUtil.getLogger(getClass());
private List<InteractionMethod> interactionMethods; private List<InteractionMethod> interactionMethods;
private LibraryWrapper wrapper; private Marinara marinara;
public InteractionRegistry(LibraryWrapper wrapper) { public InteractionRegistry(Marinara marinara) {
this.interactionMethods = new ArrayList<>(); this.interactionMethods = new ArrayList<>();
this.wrapper = wrapper; this.marinara = marinara;
wrapper.subscribeInteractions(this::handle); marinara.getWrapper().subscribeInteractions(this::handle);
} }
public void addInteractions(InteractionHandler interactionHandler) { public void addInteractions(InteractionHandler interactionHandler) {
for (Method method : interactionHandler.getClass().getMethods()) { for (Method method : interactionHandler.getClass().getMethods()) {
InteractionMethod iMethod = InteractionMethod.create(method, interactionHandler, wrapper); InteractionMethod iMethod = InteractionMethod.create(method, interactionHandler, marinara);
if (iMethod != null) if (iMethod != null) {
this.interactionMethods.add(iMethod); this.interactionMethods.add(iMethod);
logger.debug("Added {} method from {}", iMethod.getMethod().getName(), interactionHandler.getClass().getSimpleName());
}
} }
logger.info("Added all Interactions from {}", interactionHandler.getClass().getSimpleName());
} }
public void registerCommands() { public void registerCommands() {
@@ -46,16 +53,26 @@ public class InteractionRegistry {
appDef.get().addExecutableCommand(def); appDef.get().addExecutableCommand(def);
else else
defs.add(new SlashCommandDefinition(def.applicationCommand()).addExecutableCommand(def)); defs.add(new SlashCommandDefinition(def.applicationCommand()).addExecutableCommand(def));
logger.debug("Added Executable Command {}{}{} for registration",
def.applicationCommand().name(),
def.subCommandGroup() == null ? "" : "." + def.subCommandGroup().name(),
def.subCommand() == null ? "" : "." + def.subCommand().name()
);
}); });
wrapper.registerSlashCommands(defs.toArray(new SlashCommandDefinition[0])); marinara.getWrapper().registerSlashCommands(defs.toArray(SlashCommandDefinition[]::new));
logger.info("Registered all SlashCommands");
} }
public void handle(Object context) { public void handle(Object context) {
InteractionType type = marinara.getWrapper().getInteractionType(context.getClass());
logger.debug("Received {} interaction ", context);
interactionMethods.forEach((m) -> { interactionMethods.forEach((m) -> {
InteractionType type = wrapper.getInteractionType(context.getClass()); if (m.getType().equals(type) && m.canRun(context)) {
if (m.getType().equals(type))
m.run(context); m.run(context);
logger.info("Running {} interaction using {}\ncontext: {}", type, m.getMethod().toString(), context.toString());
}
}); });
} }
} }

View File

@@ -0,0 +1,24 @@
package net.tomatentum.marinara.util;
import java.util.Properties;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.simple.SimpleLogger;
import org.apache.logging.log4j.util.PropertiesUtil;
import org.apache.logging.log4j.util.ProviderUtil;
public class LoggerUtil {
public static Logger getLogger(String name) {
if (ProviderUtil.hasProviders()) {
return LogManager.getLogger(name);
}else
return new SimpleLogger(name, Level.DEBUG, true, false, true, true, "yyyy-MM-dd HH:mm:ss.SSSZ", null,
new PropertiesUtil(new Properties()), System.out);
}
public static Logger getLogger(Class<?> clazz) {
return getLogger(clazz.getName());
}
}

View File

@@ -2,9 +2,10 @@ package net.tomatentum.marinara.util;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import net.tomatentum.marinara.interaction.commands.annotation.SlashCommand; import java.util.Arrays;
import net.tomatentum.marinara.interaction.commands.annotation.SubCommand; import java.util.List;
import java.util.Objects;
public final class ReflectionUtil { public final class ReflectionUtil {
@@ -21,19 +22,86 @@ public final class ReflectionUtil {
method.getDeclaringClass().getAnnotation(annotationClass); method.getDeclaringClass().getAnnotation(annotationClass);
} }
public static void checkValidCommandMethod(Method method) { public static int getCastDepth(Class<?> child, Class<?> parent) {
if (method.isAnnotationPresent(SlashCommand.class) &&
method.getDeclaringClass().isAnnotationPresent(SlashCommand.class)) { if (parent.equals(Object.class))
throw new RuntimeException(method.getName() + ": Can't have ApplicationCommand Annotation on Class and Method"); return Integer.MAX_VALUE;
if (!parent.isAssignableFrom(child)) {
throw new IllegalArgumentException("The specified class is not a child class of the specified parent.");
} }
if (!isAnnotationPresent(method, SlashCommand.class)) int depth = 0;
throw new RuntimeException(method.getName() + ": Missing ApplicationCommand Annotation on either Class or Method"); Class<?> curr = child;
List<Class<?>> parents = new ArrayList<>();
if ((method.isAnnotationPresent(SubCommand.class) && while (!curr.equals(parent)) {
!isAnnotationPresent(method, SlashCommand.class))) { depth++;
throw new RuntimeException(method.getName() + ": Missing ApplicationCommand Annotation on either Method or Class"); parents.add(curr.getSuperclass());
parents.addAll(Arrays.asList(curr.getInterfaces()));
for (Class<?> currParent : parents) {
if (currParent != null && parent.isAssignableFrom(currParent)) {
curr = currParent;
break;
}
}
parents.clear();
} }
return depth;
} }
public static Method getMostSpecificMethod(Method[] methods, Class<?>... parameters) {
List<Method> compatibleMethods = Arrays.stream(methods)
.filter(x -> isMethodCallable(x, parameters))
.toList();
if (compatibleMethods.size() == 0)
throw new IllegalArgumentException("There are no compatible Methods provided");
for (int i = 0; i < parameters.length; i++) {
final int currI = i;
Class<?>[] parameterTypes = compatibleMethods.stream()
.map(x -> x.getParameterTypes()[currI])
.toArray(x -> new Class[x]);
Class<?> mostSpecific = getMostSpecificClass(parameterTypes, parameters[i]);
compatibleMethods = compatibleMethods.stream()
.filter(x -> Objects.equals(x.getParameterTypes()[currI], mostSpecific))
.toList();
}
return compatibleMethods.getFirst();
}
public static Class<?> getMostSpecificClass(Class<?>[] classes, Class<?> base) {
int min = Integer.MAX_VALUE;
Class<?> currMostSpecific = null;
for (Class<?> currClass : classes) {
int currCastDepth = getCastDepth(base, currClass);
if (currCastDepth <= min) {
min = currCastDepth;
currMostSpecific = currClass;
}
}
return currMostSpecific;
}
public static boolean isMethodCallable(Method method, Class<?>... parameters) {
if (!Objects.equals(method.getParameterCount(), parameters.length))
return false;
Class<?>[] methodParams = method.getParameterTypes();
for (int i = 0; i < parameters.length; i++) {
if (!methodParams[i].isAssignableFrom(parameters[i]))
return false;
}
return true;
}
public static String getFullMethodName(Method method) {
return method.getClass().getName() + "." + method.getName();
}
} }

View File

@@ -29,7 +29,7 @@ dependencies {
// Apply a specific Java toolchain to ease working on different environments. // Apply a specific Java toolchain to ease working on different environments.
java { java {
toolchain { toolchain {
languageVersion = JavaLanguageVersion.of(21) languageVersion = JavaLanguageVersion.of(23)
} }
} }

View File

@@ -0,0 +1,41 @@
package net.tomatentum.marinara.wrapper.javacord.checks;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Optional;
import org.javacord.api.entity.permission.PermissionType;
import org.javacord.api.entity.server.Server;
import org.javacord.api.interaction.InteractionBase;
import net.tomatentum.marinara.checks.InteractionCheck;
public class PermissionCheck implements InteractionCheck<PermissionCheck.HasPermission> {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface HasPermission {
public PermissionType[] value();
}
@Override
public boolean preExec(Object context, HasPermission annotation) {
throw new UnsupportedOperationException("Unimplemented method 'preExec'");
}
public boolean preExec(InteractionBase context, HasPermission annotation) {
Optional<Server> server = context.getServer();
if (!server.isPresent())
return false;
return server.get().hasPermissions(context.getUser(), annotation.value());
}
@Override
public void postExec(Object context, HasPermission annotation) {
}
}

View File

@@ -20,7 +20,7 @@ public class ButtonTest {
LibraryWrapper wrapper = new JavacordWrapper(new DiscordApiMock()); //null okay as we don't use the discord API in this test. LibraryWrapper wrapper = new JavacordWrapper(new DiscordApiMock()); //null okay as we don't use the discord API in this test.
Marinara marinara = Marinara.load(wrapper); Marinara marinara = Marinara.load(wrapper);
marinara.getRegistry().addInteractions(new TestButton()); marinara.getRegistry().addInteractions(new TestButton());
wrapper.handleInteraction(new ButtonInteractionMock()); wrapper.handleInteraction(new ButtonInteractionMock("test"));
assertTrue(TestButton.didRun); assertTrue(TestButton.didRun);
} }

View File

@@ -0,0 +1,47 @@
package net.tomatentum.marinara.test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.javacord.api.entity.permission.PermissionType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import net.tomatentum.marinara.Marinara;
import net.tomatentum.marinara.test.mocks.ButtonInteractionMock;
import net.tomatentum.marinara.test.mocks.DiscordApiMock;
import net.tomatentum.marinara.test.mocks.ServerMock;
import net.tomatentum.marinara.wrapper.LibraryWrapper;
import net.tomatentum.marinara.wrapper.javacord.JavacordWrapper;
import net.tomatentum.marinara.wrapper.javacord.checks.PermissionCheck;
@TestInstance(Lifecycle.PER_CLASS)
public class InteractionCheckTest {
@Test
public void testInteractionCheck() {
LibraryWrapper wrapper = new JavacordWrapper(new DiscordApiMock());
Marinara marinara = Marinara.load(wrapper);
marinara.getCheckRegistry().addCheck(new TestInteractionCheck());
marinara.getRegistry().addInteractions(new TestButton());
wrapper.handleInteraction(new ButtonInteractionMock("test"));
assertTrue(TestInteractionCheck.preExecuted);
assertTrue(TestInteractionCheck.postExecuted);
}
@Test
public void testPermissionCheck() {
LibraryWrapper wrapper = new JavacordWrapper(new DiscordApiMock());
Marinara marinara = Marinara.load(wrapper);
marinara.getCheckRegistry().addCheck(new PermissionCheck());
marinara.getRegistry().addInteractions(new TestButton());
wrapper.handleInteraction(new ButtonInteractionMock("permissionCheck"));
assertTrue(TestButton.didPermRun);
TestButton.didPermRun = false;
ServerMock.TESTPERMISSION = PermissionType.ATTACH_FILE;
wrapper.handleInteraction(new ButtonInteractionMock("permissionCheck"));
assertFalse(TestButton.didPermRun);
}
}

View File

@@ -4,18 +4,22 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.javacord.api.entity.channel.TextChannel; import org.javacord.api.entity.channel.TextChannel;
import org.javacord.api.entity.message.Message; import org.javacord.api.entity.message.Message;
import org.javacord.api.entity.permission.PermissionType;
import org.javacord.api.entity.server.Server; import org.javacord.api.entity.server.Server;
import org.javacord.api.entity.user.User; import org.javacord.api.entity.user.User;
import org.javacord.api.interaction.ButtonInteraction; import org.javacord.api.interaction.ButtonInteraction;
import net.tomatentum.marinara.interaction.InteractionHandler; import net.tomatentum.marinara.interaction.InteractionHandler;
import net.tomatentum.marinara.interaction.annotation.Button; import net.tomatentum.marinara.interaction.annotation.Button;
import net.tomatentum.marinara.test.TestInteractionCheck.TestCheck;
import net.tomatentum.marinara.wrapper.javacord.checks.PermissionCheck.HasPermission;
public class TestButton implements InteractionHandler { public class TestButton implements InteractionHandler {
public static boolean didRun = false; public static boolean didRun = false;
@Button("test") @Button("test")
@TestCheck
public void exec(ButtonInteraction interaction, TextChannel channel, Message message, User member, Server server) { public void exec(ButtonInteraction interaction, TextChannel channel, Message message, User member, Server server) {
assertNotNull(interaction); assertNotNull(interaction);
assertNotNull(channel); assertNotNull(channel);
@@ -26,4 +30,13 @@ public class TestButton implements InteractionHandler {
System.out.println("Success!"); System.out.println("Success!");
} }
public static boolean didPermRun = false;
@Button("permissionCheck")
@HasPermission({PermissionType.ADMINISTRATOR})
public void exec(ButtonInteraction interaction) {
didPermRun = true;
System.out.println("It worked!");
}
} }

View File

@@ -0,0 +1,37 @@
package net.tomatentum.marinara.test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import net.tomatentum.marinara.checks.InteractionCheck;
public class TestInteractionCheck implements InteractionCheck<TestInteractionCheck.TestCheck> {
public static boolean preExecuted = false;
public static boolean postExecuted = false;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public static @interface TestCheck {
}
@Override
public boolean preExec(Object context, TestCheck annotation) {
assertNotNull(annotation);
assertNotNull(context);
preExecuted = true;
return true;
}
@Override
public void postExec(Object context, TestCheck annotation) {
assertNotNull(annotation);
assertNotNull(context);
postExecuted = true;
}
}

View File

@@ -23,6 +23,12 @@ import org.javacord.api.interaction.callback.InteractionOriginalResponseUpdater;
public class ButtonInteractionMock implements ButtonInteraction { public class ButtonInteractionMock implements ButtonInteraction {
private String customId;
public ButtonInteractionMock(String customId) {
this.customId = customId;
}
@Override @Override
public Message getMessage() { public Message getMessage() {
return new MessageMock(); return new MessageMock();
@@ -30,7 +36,7 @@ public class ButtonInteractionMock implements ButtonInteraction {
@Override @Override
public String getCustomId() { public String getCustomId() {
return "test"; return this.customId;
} }
@Override @Override

View File

@@ -1,5 +1,7 @@
package net.tomatentum.marinara.test.mocks; package net.tomatentum.marinara.test.mocks;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.time.Instant; import java.time.Instant;
import java.util.Collection; import java.util.Collection;
import java.util.EnumSet; import java.util.EnumSet;
@@ -27,6 +29,7 @@ import org.javacord.api.entity.channel.ServerTextChannel;
import org.javacord.api.entity.channel.ServerThreadChannel; import org.javacord.api.entity.channel.ServerThreadChannel;
import org.javacord.api.entity.channel.ServerVoiceChannel; import org.javacord.api.entity.channel.ServerVoiceChannel;
import org.javacord.api.entity.emoji.KnownCustomEmoji; import org.javacord.api.entity.emoji.KnownCustomEmoji;
import org.javacord.api.entity.permission.PermissionType;
import org.javacord.api.entity.permission.Role; import org.javacord.api.entity.permission.Role;
import org.javacord.api.entity.server.ActiveThreads; import org.javacord.api.entity.server.ActiveThreads;
import org.javacord.api.entity.server.Ban; import org.javacord.api.entity.server.Ban;
@@ -2259,5 +2262,12 @@ public class ServerMock implements Server {
// TODO Auto-generated method stub // TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'getSystemChannelFlags'"); throw new UnsupportedOperationException("Unimplemented method 'getSystemChannelFlags'");
} }
public static PermissionType TESTPERMISSION = PermissionType.ADMINISTRATOR;
@Override
public boolean hasPermissions(User user, PermissionType... type) {
assertNotNull(user);
assertNotNull(type);
return TESTPERMISSION.equals(type[0]);
}
} }