From 0715c4ab9d39a05e4eca71bedc5a7625aa4fd7b5 Mon Sep 17 00:00:00 2001 From: broccolai Date: Tue, 20 Oct 2020 08:50:32 +0100 Subject: [PATCH] Add JDA example Basic example also showing a basic implementation of the permission mapper --- examples/example-jda/build.gradle | 18 +++ .../examples/jda/CustomUser.java | 64 ++++++++ .../examples/jda/ExampleBot.java | 149 ++++++++++++++++++ .../examples/jda/GuildUser.java | 65 ++++++++ .../examples/jda/PermissionRegistry.java | 78 +++++++++ .../examples/jda/PrivateUser.java | 54 +++++++ .../examples/jda/package-info.java | 28 ++++ settings.gradle | 2 + 8 files changed, 458 insertions(+) create mode 100644 examples/example-jda/build.gradle create mode 100644 examples/example-jda/src/main/java/cloud/commandframework/examples/jda/CustomUser.java create mode 100644 examples/example-jda/src/main/java/cloud/commandframework/examples/jda/ExampleBot.java create mode 100644 examples/example-jda/src/main/java/cloud/commandframework/examples/jda/GuildUser.java create mode 100644 examples/example-jda/src/main/java/cloud/commandframework/examples/jda/PermissionRegistry.java create mode 100644 examples/example-jda/src/main/java/cloud/commandframework/examples/jda/PrivateUser.java create mode 100644 examples/example-jda/src/main/java/cloud/commandframework/examples/jda/package-info.java diff --git a/examples/example-jda/build.gradle b/examples/example-jda/build.gradle new file mode 100644 index 00000000..5acf8220 --- /dev/null +++ b/examples/example-jda/build.gradle @@ -0,0 +1,18 @@ +apply plugin: "application" +apply plugin: "com.github.johnrengelman.shadow" + +application { + mainClassName = "cloud.commandframework.examples.jda.ExampleBot" +} + +repositories { + jcenter() +} + +dependencies { + implementation project(":cloud-jda") + implementation 'net.dv8tion:JDA:4.2.0_207' + implementation 'org.slf4j:slf4j-simple:1.7.21' +} + +build.dependsOn(shadowJar) diff --git a/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/CustomUser.java b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/CustomUser.java new file mode 100644 index 00000000..b510eab2 --- /dev/null +++ b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/CustomUser.java @@ -0,0 +1,64 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & 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 cloud.commandframework.examples.jda; + +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.User; +import org.checkerframework.checker.nullness.qual.NonNull; + +public abstract class CustomUser { + + private final User user; + private final MessageChannel channel; + + /** + * Construct a user + * + * @param user Sending user + * @param channel Channel that the message was sent in + */ + public CustomUser(final @NonNull User user, final @NonNull MessageChannel channel) { + this.user = user; + this.channel = channel; + } + + /** + * Get the user that sent the message + * + * @return Sending user + */ + public final @NonNull User getUser() { + return user; + } + + /** + * Get the channel the message was sent in + * + * @return Message channel + */ + public final @NonNull MessageChannel getChannel() { + return channel; + } + +} diff --git a/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/ExampleBot.java b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/ExampleBot.java new file mode 100644 index 00000000..1e234d79 --- /dev/null +++ b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/ExampleBot.java @@ -0,0 +1,149 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & 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 cloud.commandframework.examples.jda; + +import cloud.commandframework.Command; +import cloud.commandframework.arguments.standard.StringArgument; +import cloud.commandframework.execution.CommandExecutionCoordinator; +import cloud.commandframework.jda.JDACommandManager; +import cloud.commandframework.jda.JDAGuildSender; +import cloud.commandframework.jda.JDAPrivateSender; +import cloud.commandframework.jda.parsers.UserArgument; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.requests.GatewayIntent; +import net.dv8tion.jda.api.utils.ChunkingFilter; +import net.dv8tion.jda.api.utils.MemberCachePolicy; +import org.checkerframework.checker.nullness.qual.NonNull; + +import javax.security.auth.login.LoginException; + +public final class ExampleBot { + + private ExampleBot() { + throw new UnsupportedOperationException(); + } + + /** + * Starts the bot + * + * @param args Arguments to start the bot + * @throws InterruptedException When the jda instance does not ready correctly + * @throws LoginException If the bots token isn't correct + */ + public static void main(final @NonNull String[] args) throws InterruptedException, LoginException { + final JDA jda = JDABuilder.createDefault(System.getProperty("token")) + .setAutoReconnect(true) + .setChunkingFilter(ChunkingFilter.ALL) + .setMemberCachePolicy(MemberCachePolicy.ALL) + .enableIntents(GatewayIntent.GUILD_MEMBERS) + .setActivity(Activity.playing("GAMES")) + .build(); + + final PermissionRegistry permissionRegistry = new PermissionRegistry(); + + final JDACommandManager commandManager = new JDACommandManager<>( + jda, + message -> "!", + (sender, permission) -> permissionRegistry.hasPermission(sender.getUser().getIdLong(), permission), + CommandExecutionCoordinator.simpleCoordinator(), + sender -> { + if (sender instanceof JDAPrivateSender) { + JDAPrivateSender jdaPrivateSender = (JDAPrivateSender) sender; + return new PrivateUser(jdaPrivateSender.getUser(), jdaPrivateSender.getPrivateChannel()); + } + + if (sender instanceof JDAGuildSender) { + JDAGuildSender jdaGuildSender = (JDAGuildSender) sender; + return new GuildUser(jdaGuildSender.getMember(), jdaGuildSender.getTextChannel()); + } + + throw new UnsupportedOperationException(); + }, + user -> { + if (user instanceof PrivateUser) { + PrivateUser privateUser = (PrivateUser) user; + return new JDAPrivateSender(null, privateUser.getUser(), privateUser.getPrivateChannel()); + } + + if (user instanceof GuildUser) { + GuildUser guildUser = (GuildUser) user; + return new JDAGuildSender(null, guildUser.getMember(), guildUser.getTextChannel()); + } + + throw new UnsupportedOperationException(); + } + ); + + commandManager.command(commandManager + .commandBuilder("ping") + .handler(context -> { + context.getSender().getChannel().sendMessage("pong").complete(); + })); + + final Command.Builder builder = commandManager.commandBuilder("permission"); + + commandManager.command(builder + .literal("add") + .argument(UserArgument.of("user")) + .argument(StringArgument.single("perm")) + .handler(context -> { + final User user = context.get("user"); + final String perm = context.get("perm"); + + permissionRegistry.add(user.getIdLong(), perm); + context.getSender().getChannel().sendMessage("permission added").complete(); + })); + + commandManager.command(builder + .literal("remove") + .argument(UserArgument.of("user")) + .argument(StringArgument.single("perm")) + .handler(context -> { + final User user = context.get("user"); + final String perm = context.get("perm"); + + permissionRegistry.remove(user.getIdLong(), perm); + context.getSender().getChannel().sendMessage("permission removed").complete(); + })); + + commandManager.command(commandManager + .commandBuilder("kick") + .senderType(GuildUser.class) + .permission("kick") + .argument(UserArgument.of("user")) + .handler(context -> { + final GuildUser guildUser = (GuildUser) context.getSender(); + final TextChannel textChannel = guildUser.getTextChannel(); + final User user = context.get("user"); + + textChannel.getGuild().kick(user.getId()).complete(); + textChannel.sendMessage(user.getName() + " kicked").complete(); + })); + } + +} diff --git a/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/GuildUser.java b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/GuildUser.java new file mode 100644 index 00000000..87842c80 --- /dev/null +++ b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/GuildUser.java @@ -0,0 +1,65 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & 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 cloud.commandframework.examples.jda; + +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.TextChannel; +import org.checkerframework.checker.nullness.qual.NonNull; + +public final class GuildUser extends CustomUser { + + private final Member member; + private final TextChannel channel; + + /** + * Construct a Guild user + * + * @param member Guild member that sent the message + * @param channel Text channel that the message was sent in + */ + public GuildUser(final @NonNull Member member, final @NonNull TextChannel channel) { + super(member.getUser(), channel); + this.member = member; + this.channel = channel; + } + + /** + * Get the member that sent the message + * + * @return Sending member + */ + public @NonNull Member getMember() { + return member; + } + + /** + * Get the text channel the message was sent in + * + * @return Message channel + */ + public @NonNull TextChannel getTextChannel() { + return channel; + } + +} diff --git a/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/PermissionRegistry.java b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/PermissionRegistry.java new file mode 100644 index 00000000..417568b3 --- /dev/null +++ b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/PermissionRegistry.java @@ -0,0 +1,78 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & 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 cloud.commandframework.examples.jda; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public final class PermissionRegistry { + + private final Map> permissions = new HashMap<>(); + + /** + * Add a permission to a user + * + * @param userId Users id + * @param permission Permission to add + */ + public void add(final @NonNull Long userId, final @NonNull String permission) { + this.getPermissions(userId).add(permission.toLowerCase()); + } + + /** + * Remove a permission from a user + * + * @param userId Users id + * @param permission Permission to remove + */ + public void remove(final @NonNull Long userId, final @NonNull String permission) { + this.getPermissions(userId).remove(permission.toLowerCase()); + } + + /** + * Check if a user has a specific permission + * + * @param userId Users id + * @param permission Permission to check + * @return True if the user has a permission + */ + public boolean hasPermission(final @NonNull Long userId, final @Nullable String permission) { + if (permission == null) { + return true; + } + + return this.getPermissions(userId).contains(permission.toLowerCase()); + } + + private Set getPermissions(final @NonNull Long userId) { + this.permissions.putIfAbsent(userId, new HashSet<>()); + return this.permissions.get(userId); + } + +} diff --git a/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/PrivateUser.java b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/PrivateUser.java new file mode 100644 index 00000000..ea75b2e6 --- /dev/null +++ b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/PrivateUser.java @@ -0,0 +1,54 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & 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 cloud.commandframework.examples.jda; + +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.User; +import org.checkerframework.checker.nullness.qual.NonNull; + +public final class PrivateUser extends CustomUser { + + private final PrivateChannel privateChannel; + + /** + * Construct a Private user + * + * @param user User that sent the message + * @param channel Text channel that the message was sent in + */ + public PrivateUser(final @NonNull User user, final @NonNull PrivateChannel channel) { + super(user, channel); + this.privateChannel = channel; + } + + /** + * Get the private channel the message was sent in + * + * @return Private channel + */ + public @NonNull PrivateChannel getPrivateChannel() { + return privateChannel; + } + +} diff --git a/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/package-info.java b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/package-info.java new file mode 100644 index 00000000..adf19615 --- /dev/null +++ b/examples/example-jda/src/main/java/cloud/commandframework/examples/jda/package-info.java @@ -0,0 +1,28 @@ +// +// MIT License +// +// Copyright (c) 2020 Alexander Söderberg & 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. +// + +/** + * JDA example bot + */ +package cloud.commandframework.examples.jda; diff --git a/settings.gradle b/settings.gradle index 41cd99f8..9c1fc6bc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,6 +13,7 @@ include(':cloud-javacord') include(':cloud-jda') include(':example-bukkit') include(':example-javacord') +include(':example-jda') include(':cloud-tasks') include(':cloud-sponge') include(':example-velocity') @@ -28,6 +29,7 @@ project(':cloud-javacord').projectDir = file('cloud-discord/cloud-javacord') project(':cloud-jda').projectDir = file('cloud-discord/cloud-jda') project(':example-bukkit').projectDir = file('examples/example-bukkit') project(':example-javacord').projectDir = file('examples/example-javacord') +project(':example-jda').projectDir = file('examples/example-jda') project(':cloud-sponge').projectDir = file('cloud-minecraft/cloud-sponge') project(':example-velocity').projectDir = file('examples/example-velocity') project(':example-bungee').projectDir = file('examples/example-bungee')