diff --git a/src/examples/java/SlashBotExample.java b/src/examples/java/SlashBotExample.java index 8d9507506b..d3be59e103 100644 --- a/src/examples/java/SlashBotExample.java +++ b/src/examples/java/SlashBotExample.java @@ -24,6 +24,7 @@ import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.interactions.InteractionHook; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.OptionData; @@ -53,8 +54,10 @@ public static void main(String[] args) throws LoginException .addOptions(new OptionData(USER, "user", "The user to ban") // USER type allows to include members of the server or other users by id .setRequired(true)) // This command requires a parameter .addOptions(new OptionData(INTEGER, "del_days", "Delete messages from the past days.") // This is optional - .setRequiredRange(0, 7)) // Only allow values between 0 and 7 (inclusive) + .setRequiredRange(0, 7)) // Only allow values between 0 and 7 (inclusive) .addOptions(new OptionData(STRING, "reason", "The ban reason to use (default: Banned by )")) // optional reason + .setGuildOnly(true) // This way the command can only be executed from a guild, and not the DMs + .setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.BAN_MEMBERS)) // Only members with the BAN_MEMBERS permission are going to see this command ); // Simple reply commands @@ -66,11 +69,15 @@ public static void main(String[] args) throws LoginException // Commands without any inputs commands.addCommands( Commands.slash("leave", "Make the bot leave the server") + .setGuildOnly(true) // this doesn't make sense in DMs + .setDefaultPermissions(DefaultMemberPermissions.DISABLED) // only admins should be able to use this command. ); commands.addCommands( Commands.slash("prune", "Prune messages from this channel") .addOption(INTEGER, "amount", "How many messages to prune (Default 100)") // simple optional argument + .setGuildOnly(true) + .setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MESSAGE_MANAGE)) ); // Send the new set of commands to discord, this will override any existing global commands with the new set provided here diff --git a/src/main/java/net/dv8tion/jda/api/audit/ActionType.java b/src/main/java/net/dv8tion/jda/api/audit/ActionType.java index 11064cf3fe..bab82e1c6d 100644 --- a/src/main/java/net/dv8tion/jda/api/audit/ActionType.java +++ b/src/main/java/net/dv8tion/jda/api/audit/ActionType.java @@ -533,6 +533,11 @@ public enum ActionType */ THREAD_DELETE(112, TargetType.THREAD), + /** + * A moderator updated the privileges for an application + */ + APPLICATION_COMMAND_PRIVILEGES_UPDATE(121, TargetType.INTEGRATION), + UNKNOWN(-1, TargetType.UNKNOWN); private final int key; diff --git a/src/main/java/net/dv8tion/jda/api/entities/Guild.java b/src/main/java/net/dv8tion/jda/api/entities/Guild.java index 9719774997..d8c894d02d 100644 --- a/src/main/java/net/dv8tion/jda/api/entities/Guild.java +++ b/src/main/java/net/dv8tion/jda/api/entities/Guild.java @@ -25,9 +25,10 @@ import net.dv8tion.jda.api.entities.templates.Template; import net.dv8tion.jda.api.exceptions.InsufficientPermissionException; import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.PrivilegeConfig; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.Commands; -import net.dv8tion.jda.api.interactions.commands.privileges.CommandPrivilege; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; import net.dv8tion.jda.api.managers.AudioManager; import net.dv8tion.jda.api.managers.GuildManager; import net.dv8tion.jda.api.managers.GuildStickerManager; @@ -285,194 +286,61 @@ default RestAction deleteCommandById(long commandId) } /** - * Retrieves the {@link CommandPrivilege CommandPrivileges} for the command with the specified ID. + * Retrieves the {@link IntegrationPrivilege IntegrationPrivileges} for the target with the specified ID. + *
The ID can either be of a Command or Application! * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. + *

Moderators of a guild can modify these privileges through the Integrations Menu * - *

If there is no command with the provided ID, + *

If there is no command or application with the provided ID, * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} * - * @param commandId - * The id of the command, this can be global or guild command + * @param targetId + * The id of the command (global or guild), or application * * @throws IllegalArgumentException * If the id is not a valid snowflake * - * @return {@link RestAction} - Type: {@link List} of {@link CommandPrivilege} + * @return {@link RestAction} - Type: {@link List} of {@link IntegrationPrivilege} */ @Nonnull @CheckReturnValue - RestAction> retrieveCommandPrivilegesById(@Nonnull String commandId); + RestAction> retrieveIntegrationPrivilegesById(@Nonnull String targetId); /** - * Retrieves the {@link CommandPrivilege CommandPrivileges} for the command with the specified ID. + * Retrieves the {@link IntegrationPrivilege IntegrationPrivileges} for the target with the specified ID. + *
The ID can either be of a Command or Application! * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. + *

Moderators of a guild can modify these privileges through the Integrations Menu * - *

If there is no command with the provided ID, + *

If there is no command or application with the provided ID, * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} * - * @param commandId - * The id of the command, this can be global or guild command + * @param targetId + * The id of the command (global or guild), or application * * @throws IllegalArgumentException * If the id is not a valid snowflake * - * @return {@link RestAction} - Type: {@link List} of {@link CommandPrivilege} + * @return {@link RestAction} - Type: {@link List} of {@link IntegrationPrivilege} */ @Nonnull @CheckReturnValue - default RestAction> retrieveCommandPrivilegesById(long commandId) + default RestAction> retrieveIntegrationPrivilegesById(long targetId) { - return retrieveCommandPrivilegesById(Long.toUnsignedString(commandId)); + return retrieveIntegrationPrivilegesById(Long.toUnsignedString(targetId)); } /** - * Retrieves the {@link CommandPrivilege CommandPrivileges} for the commands in this guild. - *
The RestAction provides a {@link Map} from the command id to the list of privileges. - * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. - * - * @return {@link RestAction} - Type: {@link Map} from {@link String} Command ID to {@link List} of {@link CommandPrivilege} - */ - @Nonnull - @CheckReturnValue - RestAction>> retrieveCommandPrivileges(); - - /** - * Updates the list of {@link CommandPrivilege CommandPrivileges} for the specified command. - *
Note that commands are enabled by default for all members of a guild, which means you can only blacklist roles and members using this method. - * To change this behavior, use {@link CommandData#setDefaultEnabled(boolean)} on your command. - * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. - * - *

If there is no command with the provided ID, - * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} - * - * @param id - * The id of the command, this can be global or guild command - * @param privileges - * Complete list of up to 10 {@link CommandPrivilege CommandPrivileges} for this command - * - * @throws IllegalArgumentException - * If null is provided, the id is not a valid snowflake, or more than 10 privileges are provided - * - * @return {@link RestAction} - Type: {@link List} or {@link CommandPrivilege} - * The updated list of privileges for this command. - */ - @Nonnull - @CheckReturnValue - RestAction> updateCommandPrivilegesById(@Nonnull String id, @Nonnull Collection privileges); - - /** - * Updates the list of {@link CommandPrivilege CommandPrivileges} for the specified command. - *
Note that commands are enabled by default for all members of a guild, which means you can only blacklist roles and members using this method. - * To change this behavior, use {@link CommandData#setDefaultEnabled(boolean)} on your command. - * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. - * - *

If there is no command with the provided ID, - * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} - * - * @param id - * The id of the command, this can be global or guild command - * @param privileges - * Complete list of up to 10 {@link CommandPrivilege CommandPrivileges} for this command - * - * @throws IllegalArgumentException - * If null is provided, the id is not a valid snowflake, or more than 10 privileges are provided + * Retrieves the {@link IntegrationPrivilege IntegrationPrivileges} for the commands in this guild. + *
The RestAction provides a {@link PrivilegeConfig} providing the privileges of this application and its commands. * - * @return {@link RestAction} - Type: {@link List} or {@link CommandPrivilege} - * The updated list of privileges for this command. - */ - @Nonnull - @CheckReturnValue - default RestAction> updateCommandPrivilegesById(@Nonnull String id, @Nonnull CommandPrivilege... privileges) - { - Checks.noneNull(privileges, "CommandPrivileges"); - return updateCommandPrivilegesById(id, Arrays.asList(privileges)); - } - - /** - * Updates the list of {@link CommandPrivilege CommandPrivileges} for the specified command. - *
Note that commands are enabled by default for all members of a guild, which means you can only blacklist roles and members using this method. - * To change this behavior, use {@link CommandData#setDefaultEnabled(boolean)} on your command. - * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. - * - *

If there is no command with the provided ID, - * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} - * - * @param id - * The id of the command, this can be global or guild command - * @param privileges - * Complete list of up to 10 {@link CommandPrivilege CommandPrivileges} for this command - * - * @throws IllegalArgumentException - * If null is provided or more than 10 privileges are provided - * - * @return {@link RestAction} - Type: {@link List} or {@link CommandPrivilege} - * The updated list of privileges for this command. - */ - @Nonnull - @CheckReturnValue - default RestAction> updateCommandPrivilegesById(long id, @Nonnull Collection privileges) - { - return updateCommandPrivilegesById(Long.toUnsignedString(id), privileges); - } - - /** - * Updates the list of {@link CommandPrivilege CommandPrivileges} for the specified command. - *
Note that commands are enabled by default for all members of a guild, which means you can only blacklist roles and members using this method. - * To change this behavior, use {@link CommandData#setDefaultEnabled(boolean)} on your command. - * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. - * - *

If there is no command with the provided ID, - * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} - * - * @param id - * The id of the command, this can be global or guild command - * @param privileges - * Complete list of up to 10 {@link CommandPrivilege CommandPrivileges} for this command - * - * @throws IllegalArgumentException - * If null is provided or more than 10 privileges are provided - * - * @return {@link RestAction} - Type: {@link List} or {@link CommandPrivilege} - * The updated list of privileges for this command. - */ - @Nonnull - @CheckReturnValue - default RestAction> updateCommandPrivilegesById(long id, @Nonnull CommandPrivilege... privileges) - { - Checks.noneNull(privileges, "CommandPrivileges"); - return updateCommandPrivilegesById(id, Arrays.asList(privileges)); - } - - /** - * Updates the list of {@link CommandPrivilege CommandPrivileges} for the specified commands. - *
The argument for this function is a {@link Map} similar to the one returned by {@link #retrieveCommandPrivileges()}. - *
Note that commands are enabled by default for all members of a guild, which means you can only blacklist roles and members using this method. - * To change this behavior, use {@link CommandData#setDefaultEnabled(boolean)} on your command. - * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. - * - *

If there is no command with the provided ID, - * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} - * - * @param privileges - * Complete map of {@link CommandPrivilege CommandPrivileges} for each command - * - * @throws IllegalArgumentException - * If null is provided, any of the map keys is not a valid snowflake, or more than 10 privileges are provided for any command + *

Moderators of a guild can modify these privileges through the Integrations Menu * - * @return {@link RestAction} - Type: {@link Map} from {@link String} Command ID to {@link List} of {@link CommandPrivilege} - * The updated map of command privileges for this guild. + * @return {@link RestAction} - Type: {@link PrivilegeConfig} */ @Nonnull @CheckReturnValue - RestAction>> updateCommandPrivileges(@Nonnull Map> privileges); + RestAction retrieveCommandPrivileges(); /** * Retrieves the available regions for this Guild diff --git a/src/main/java/net/dv8tion/jda/api/events/interaction/command/ApplicationCommandUpdatePrivilegesEvent.java b/src/main/java/net/dv8tion/jda/api/events/interaction/command/ApplicationCommandUpdatePrivilegesEvent.java new file mode 100644 index 0000000000..f9a5efba75 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/events/interaction/command/ApplicationCommandUpdatePrivilegesEvent.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.events.interaction.command; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; +import net.dv8tion.jda.api.interactions.commands.privileges.PrivilegeTargetType; + +import javax.annotation.Nonnull; +import java.util.List; + +/** + * Indicates that the {@link IntegrationPrivilege Privileges} of an application-command on a guild changed. + *
If the moderator updates application-wide privileges instead of command, a {@link ApplicationUpdatePrivilegesEvent} will be fired instead. + * + *

Can be used to get affected Guild and {@link List} of new {@link IntegrationPrivilege Privileges} + */ +public class ApplicationCommandUpdatePrivilegesEvent extends GenericPrivilegeUpdateEvent +{ + public ApplicationCommandUpdatePrivilegesEvent(@Nonnull JDA api, long responseNumber, @Nonnull Guild guild, + long targetId, long applicationId, @Nonnull List privileges) + { + super(api, responseNumber, guild, targetId, applicationId, privileges); + } + + @Nonnull + @Override + public PrivilegeTargetType getTargetType() + { + return PrivilegeTargetType.COMMAND; + } + + /** + * The id of the command whose privileges have been changed. + * + * @return id of the command whose privileges have been changed. + */ + public long getCommandIdLong() + { + return getTargetIdLong(); + } + + /** + * The id of the command whose privileges have been changed. + * + * @return id of the command whose privileges have been changed. + */ + @Nonnull + public String getCommandId() + { + return getTargetId(); + } +} diff --git a/src/main/java/net/dv8tion/jda/api/events/interaction/command/ApplicationUpdatePrivilegesEvent.java b/src/main/java/net/dv8tion/jda/api/events/interaction/command/ApplicationUpdatePrivilegesEvent.java new file mode 100644 index 0000000000..b55ecccfcb --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/events/interaction/command/ApplicationUpdatePrivilegesEvent.java @@ -0,0 +1,46 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.events.interaction.command; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; +import net.dv8tion.jda.api.interactions.commands.privileges.PrivilegeTargetType; + +import javax.annotation.Nonnull; +import java.util.List; + +/** + * Indicates that the {@link IntegrationPrivilege Privileges} of an application changed. + *
If the moderator updates the privileges of a specific command, a {@link ApplicationCommandUpdatePrivilegesEvent} will be fired instead. + * + *

Can be used to get affected Guild and {@link List} of new {@link IntegrationPrivilege Privileges} + */ +public class ApplicationUpdatePrivilegesEvent extends GenericPrivilegeUpdateEvent +{ + public ApplicationUpdatePrivilegesEvent(@Nonnull JDA api, long responseNumber, @Nonnull Guild guild, long applicationId, @Nonnull List privileges) + { + super(api, responseNumber, guild, applicationId, applicationId, privileges); + } + + @Nonnull + @Override + public PrivilegeTargetType getTargetType() + { + return PrivilegeTargetType.INTEGRATION; + } +} diff --git a/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericPrivilegeUpdateEvent.java b/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericPrivilegeUpdateEvent.java new file mode 100644 index 0000000000..fa1a288c8d --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericPrivilegeUpdateEvent.java @@ -0,0 +1,123 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.events.interaction.command; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.guild.GenericGuildEvent; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; +import net.dv8tion.jda.api.interactions.commands.privileges.PrivilegeTargetType; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.List; + +/** + * Indicates that the privileges of an integration or its commands changed. + * + * Can be used to get affected {@link Guild} and the new {@link IntegrationPrivilege IntegrationPrivileges} + */ +public abstract class GenericPrivilegeUpdateEvent extends GenericGuildEvent +{ + private final long targetId; + private final long applicationId; + private final List privileges; + + public GenericPrivilegeUpdateEvent(@Nonnull JDA api, long responseNumber, @Nonnull Guild guild, + long targetId, long applicationId, @Nonnull List privileges) + { + super(api, responseNumber, guild); + this.targetId = targetId; + this.applicationId = applicationId; + this.privileges = Collections.unmodifiableList(privileges); + } + + /** + * The target {@link PrivilegeTargetType Type}. + * + * This can either be: + *

+ * + * @return The target type. + */ + @Nonnull + public abstract PrivilegeTargetType getTargetType(); + + /** + * The target-id. + * + * This can either be the id of an integration, or of a command. + * + * @return The target-id. + * + * @see #getTargetType() + */ + public long getTargetIdLong() + { + return targetId; + } + + /** + * The target-id. + * + * This can either be the id of an integration, or of a command. + * + * @return The target-id. + * + * @see #getTargetType() + */ + @Nonnull + public String getTargetId() + { + return Long.toUnsignedString(targetId); + } + + /** + * The id of the application of which privileges have been changed. + * + * @return id of the application of which privileges have been changed. + */ + public long getApplicationIdLong() + { + return applicationId; + } + + /** + * The id of the application of which privileges have been changed. + * + * @return id of the application of which privileges have been changed. + */ + @Nonnull + public String getApplicationId() + { + return Long.toUnsignedString(applicationId); + } + + /** + * The list of new {@link IntegrationPrivilege IntegrationPrivileges}. + * + * @return Unmodifiable list containing the new IntegrationPrivileges. + */ + @Nonnull + public List getPrivileges() + { + return privileges; + } +} diff --git a/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java b/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java index beedb9623a..fb4dfd0387 100644 --- a/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java +++ b/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java @@ -296,6 +296,11 @@ public void onEmojiRemoved(@Nonnull EmojiRemovedEvent event) {} public void onEmojiUpdateName(@Nonnull EmojiUpdateNameEvent event) {} public void onEmojiUpdateRoles(@Nonnull EmojiUpdateRolesEvent event) {} + // Application command permission update events + public void onGenericPrivilegeUpdate(@Nonnull GenericPrivilegeUpdateEvent event) {} + public void onApplicationCommandUpdatePrivileges(@Nonnull ApplicationCommandUpdatePrivilegesEvent event) {} + public void onApplicationUpdatePrivileges(@Nonnull ApplicationUpdatePrivilegesEvent event) {} + //Sticker Events public void onGuildStickerAdded(@Nonnull GuildStickerAddedEvent event) {} public void onGuildStickerRemoved(@Nonnull GuildStickerRemovedEvent event) {} diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java index c1f4afc9cc..ffdfa70418 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java @@ -21,7 +21,7 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.ISnowflake; import net.dv8tion.jda.api.interactions.commands.build.CommandData; -import net.dv8tion.jda.api.interactions.commands.privileges.CommandPrivilege; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.CommandEditAction; import net.dv8tion.jda.api.utils.TimeUtil; @@ -74,10 +74,10 @@ public interface Command extends ISnowflake CommandEditAction editCommand(); /** - * Retrieves the {@link CommandPrivilege CommandPrivileges} for this command. - *
This is a shortcut for {@link Guild#retrieveCommandPrivilegesById(String)}. + * Retrieves the {@link IntegrationPrivilege IntegrationPrivileges} for this command. + *
This is a shortcut for {@link Guild#retrieveIntegrationPrivilegesById(String)}. * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. + *

Moderators of a guild can modify these privileges through the Integrations Menu * *

If there is no command with the provided ID, * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} @@ -88,65 +88,11 @@ public interface Command extends ISnowflake * @throws IllegalArgumentException * If the guild is null * - * @return {@link RestAction} - Type: {@link List} of {@link CommandPrivilege} + * @return {@link RestAction} - Type: {@link List} of {@link IntegrationPrivilege} */ @Nonnull @CheckReturnValue - RestAction> retrievePrivileges(@Nonnull Guild guild); - - /** - * Updates the list of {@link CommandPrivilege CommandPrivileges} for this command. - *
Note that commands are enabled by default for all members of a guild, which means you can only blacklist roles and members using this method. - * To change this behavior, use {@link CommandData#setDefaultEnabled(boolean)} on your command. - * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. - * - *

If there is no command with the provided ID, - * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} - * - * @param guild - * The target guild from which to update the privileges - * @param privileges - * Complete list of {@link CommandPrivilege CommandPrivileges} for this command - * - * @throws IllegalArgumentException - * If null is provided - * @throws IllegalStateException - * If this command is not owned by this bot - * - * @return {@link RestAction} - Type: {@link List} or {@link CommandPrivilege} - * The updated list of privileges for this command. - */ - @Nonnull - @CheckReturnValue - RestAction> updatePrivileges(@Nonnull Guild guild, @Nonnull Collection privileges); - - /** - * Updates the list of {@link CommandPrivilege CommandPrivileges} for this command. - *
Note that commands are enabled by default for all members of a guild, which means you can only blacklist roles and members using this method. - * To change this behavior, use {@link CommandData#setDefaultEnabled(boolean)} on your command. - * - *

These privileges are used to restrict who can use commands through Role/User whitelists/blacklists. - * - *

If there is no command with the provided ID, - * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} - * - * @param guild - * The target guild from which to update the privileges - * @param privileges - * Complete list of {@link CommandPrivilege CommandPrivileges} for this command - * - * @throws IllegalArgumentException - * If null is provided - * @throws IllegalStateException - * If this command is not owned by this bot - * - * @return {@link RestAction} - Type: {@link List} or {@link CommandPrivilege} - * The updated list of privileges for this command. - */ - @Nonnull - @CheckReturnValue - RestAction> updatePrivileges(@Nonnull Guild guild, @Nonnull CommandPrivilege... privileges); + RestAction> retrievePrivileges(@Nonnull Guild guild); /** * Returns the {@link JDA JDA} instance of this Command @@ -180,13 +126,6 @@ public interface Command extends ISnowflake @Nonnull String getDescription(); - /** - * Whether this command is enabled for everyone by default. - * - * @return True, if everyone can use this command by default. - */ - boolean isDefaultEnabled(); - /** * The {@link Option Options} of this command. * @@ -253,6 +192,23 @@ default OffsetDateTime getTimeModified() return TimeUtil.getTimeCreated(getVersion()); } + /** + * The {@link DefaultMemberPermissions} of this command. + *
If this command has no default permission set, this returns {@link DefaultMemberPermissions#ENABLED}. + * + * @return The DefaultMemberPermissions of this command. + */ + @Nonnull + DefaultMemberPermissions getDefaultPermissions(); + + /** + * Whether the command can only be used inside a guild. + *
Always true for guild commands. + * + * @return True, if this command is restricted to guilds. + */ + boolean isGuildOnly(); + /** * Possible command types */ diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/DefaultMemberPermissions.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/DefaultMemberPermissions.java new file mode 100644 index 0000000000..e5ea94e32b --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/DefaultMemberPermissions.java @@ -0,0 +1,123 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.interactions.commands; + +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.internal.utils.Checks; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; + +/** + * Represents the default permissions for a Discord Application-Command. These permissions define the type of users that can use this command if no explicit command-specific + * privileges are set by moderators to control who can and can't use the command within a Guild. + *

For example, given a command defined with {@link net.dv8tion.jda.api.interactions.commands.build.CommandData#setDefaultPermissions CommandData#setDefaultPermissions} as command.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permissions.BAN_MEMBERS)) + * any user with the {@link Permission#BAN_MEMBERS} permission would be able to use the command by default. + */ +public class DefaultMemberPermissions +{ + /** + * Default permissions of a command with no restrictions applied. (Everyone can see and access this command by default) + */ + public static final DefaultMemberPermissions ENABLED = new DefaultMemberPermissions(null); + + /** + * "Empty" permissions of a command. + *
Only members with the {@link Permission#ADMINISTRATOR ADMINISTRATOR} permission can see and access this command by default. + */ + public static final DefaultMemberPermissions DISABLED = new DefaultMemberPermissions(0L); + + private final Long permissions; + + private DefaultMemberPermissions(@Nullable Long permissions) + { + this.permissions = permissions; + } + + /** + * Raw permission integer representing the default permissions of a command. + *
This returns null if it is of type {@link DefaultMemberPermissions#ENABLED ENABLED} + *
If the default member permissions are {@link DefaultMemberPermissions#DISABLED DISABLED}, this returns 0 + * + * @return Raw permission integer representing the default member permissions of a command + */ + @Nullable + public Long getPermissionsRaw() + { + return permissions; + } + + /** + * Returns a DefaultMemberPermissions instance with the predefined permissions a member must have to see and access a command. + * + *
If the passed Collection is empty, this returns {@link DefaultMemberPermissions#ENABLED ENABLED} + * + * @param permissions + * Collection of {@link Permission Permissions} + * + * @throws IllegalArgumentException + * If any of the passed Permission is null + * + * @return DefaultMemberPermissions instance with the predefined permissions + */ + @Nonnull + public static DefaultMemberPermissions enabledFor(@Nonnull Collection permissions) + { + Checks.noneNull(permissions, "Permissions"); + if (permissions.isEmpty()) + return ENABLED; + + return enabledFor(Permission.getRaw(permissions)); + } + + /** + * Returns a DefaultMemberPermissions instance with the predefined permissions a member must have to see and access a command. + * + *
If the passed Array is empty, this returns {@link DefaultMemberPermissions#ENABLED ENABLED} + * + * @param permissions + * Vararg of {@link Permission Permissions} + * + * @throws IllegalArgumentException + * If any of the passed Permission is null + * + * @return DefaultMemberPermissions instance with the predefined permissions + */ + @Nonnull + public static DefaultMemberPermissions enabledFor(@Nonnull Permission... permissions) + { + return enabledFor(Arrays.asList(permissions)); + } + + /** + * Returns a DefaultMemberPermissions instance with the predefined permissions a member must have to see and access a command. + * + *
If the passed permission offset is 0, this returns {@link DefaultMemberPermissions#ENABLED ENABLED} + * + * @param permissions + * Raw permission bitset + * + * @return DefaultMemberPermissions instance with the predefined permissions + */ + @Nonnull + public static DefaultMemberPermissions enabledFor(long permissions) + { + return new DefaultMemberPermissions(permissions); + } +} diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/PrivilegeConfig.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/PrivilegeConfig.java new file mode 100644 index 0000000000..c18ab6e5fb --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/PrivilegeConfig.java @@ -0,0 +1,143 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.interactions.commands; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.SelfUser; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; +import net.dv8tion.jda.internal.utils.Checks; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** + * A PrivilegeConfig is the collection of moderator defined {@link IntegrationPrivilege privileges} set on a specific application and its commands + * that define what channels the application can be used in and what users/roles are allowed to use it. + * These privileges are set by moderators in the guild who have access to the guild's integrations page and permissions to edit them. + * + * @see Guild#retrieveCommandPrivileges() + */ +public class PrivilegeConfig +{ + private final Guild guild; + private final Map> privileges; + + public PrivilegeConfig(@Nonnull Guild guild, @Nonnull Map> privileges) + { + this.guild = guild; + this.privileges = Collections.unmodifiableMap(privileges); + } + + /** + * The guild in which this PrivilegeConfig is applied in. + * + * @return Guild in which this PrivilegeConfig is applied in. + */ + @Nonnull + public Guild getGuild() + { + return guild; + } + + /** + * The JDA-instance. + * + * @return The JDA-instance. + */ + @Nonnull + public JDA getJDA() + { + return guild.getJDA(); + } + + /** + * The {@link IntegrationPrivilege IntegrationPrivileges} that have been applied to this application in this guild. + * + *
If the privileges are "Synced" (No custom config applied), this will return null. + * + *

This does not include privileges applied to a command itself. Use {@link #getCommandPrivileges(String)} for that. + * + * @return Immutable List containing all IntegrationPrivileges that have been applied to this application in this guild. + */ + @Nullable + public List getApplicationPrivileges() + { + return getCommandPrivileges(getJDA().getSelfUser().getApplicationId()); + } + + /** + * The {@link IntegrationPrivilege IntegrationPrivileges} that have been applied to the command with the given id in this guild. + * + *
If the privileges are "Synced" (No custom config applied), or a command with this id doesn't exist, this will return null. + * + *

This does not include privileges applied to the application directly. Use {@link #getApplicationPrivileges()} for that. + * + * @param id + * The id of the command + * + * @throws IllegalArgumentException + * If the provided id is null + * + * @return Immutable List containing all IntegrationPrivileges that have been applied to the command with the given id in this guild. + */ + @Nullable + public List getCommandPrivileges(@Nonnull String id) + { + Checks.notNull(id, "Id"); + return privileges.get(id); + } + + /** + * The {@link IntegrationPrivilege IntegrationPrivileges} that have been applied to the supplied {@link Command}. + * + *
If the privileges are "Synced" (No custom config applied), or this command no longer exists, this will return null. + * + *

This does not include privileges applied to the application directly. Use {@link #getApplicationPrivileges()} for that. + * + * @param command + * The {@link Command} to get the privileges from + * + * @throws IllegalArgumentException + * If the provided command is null + * + * @return Immutable List containing all IntegrationPrivileges that have been applied to the command in this guild. + */ + @Nullable + public List getCommandPrivileges(@Nonnull Command command) + { + Checks.notNull(command, "Command"); + return privileges.get(command.getId()); + } + + /** + * Map containing all privileges, with the command-id as the Key, and a List of {@link IntegrationPrivilege} as Value. + * + *
If {@link #getApplicationPrivileges()} is not null, this will also contain the privileges applied directly + * on this application with {@link SelfUser#getApplicationId()} as the Key. + * + * @return Unmodifiable Map containing all privileges on this guild. + */ + @Nonnull + public Map> getAsMap() + { + return privileges; + } +} diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/CommandData.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/CommandData.java index b5f5dd4fa3..a323a4b9a1 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/CommandData.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/CommandData.java @@ -16,9 +16,8 @@ package net.dv8tion.jda.api.interactions.commands.build; -import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.Command; -import net.dv8tion.jda.api.interactions.commands.privileges.CommandPrivilege; import net.dv8tion.jda.api.utils.data.DataObject; import net.dv8tion.jda.api.utils.data.SerializableData; import net.dv8tion.jda.internal.interactions.CommandDataImpl; @@ -26,7 +25,6 @@ import javax.annotation.Nonnull; import java.util.Collection; -import java.util.Map; /** * Builder for Application Commands. @@ -51,19 +49,32 @@ public interface CommandData extends SerializableData CommandData setName(@Nonnull String name); /** - * Whether this command is available to everyone by default. - *
If this is disabled, you need to explicitly whitelist users and roles per guild. + * Sets the {@link net.dv8tion.jda.api.Permission Permissions} that a user must have in a specific channel to be able to use this command. + *
By default, everyone can use this command ({@link DefaultMemberPermissions#ENABLED}). Additionally, a command can be disabled for everyone but admins via {@link DefaultMemberPermissions#DISABLED}. + *

These configurations can be overwritten by moderators in each guild. See {@link Command#retrievePrivileges(net.dv8tion.jda.api.entities.Guild)} to get moderator defined overrides. * - *

You can use {@link CommandPrivilege} to enable or disable this command per guild for roles and members of the guild. - * See {@link Command#updatePrivileges(Guild, CommandPrivilege...)} and {@link Guild#updateCommandPrivileges(Map)}. + * @param permission + * {@link DefaultMemberPermissions} representing the default permissions of this command. * - * @param enabled - * True, if this command is enabled by default for everyone. (Default: true) + * @return The builder instance, for chaining + * + * @see DefaultMemberPermissions#ENABLED + * @see DefaultMemberPermissions#DISABLED + */ + @Nonnull + CommandData setDefaultPermissions(@Nonnull DefaultMemberPermissions permission); + + /** + * Sets whether this command is only usable in a guild (Default: false). + *
This only has an effect if this command is registered globally. + * + * @param guildOnly + * Whether to restrict this command to guilds * * @return The builder instance, for chaining */ @Nonnull - CommandData setDefaultEnabled(boolean enabled); + CommandData setGuildOnly(boolean guildOnly); /** * The current command name @@ -74,22 +85,32 @@ public interface CommandData extends SerializableData String getName(); /** - * Whether this command is available to everyone by default. - * - * @return True, if this command is enabled to everyone by default + * The {@link Command.Type} * - * @see #setDefaultEnabled(boolean) - * @see CommandPrivilege + * @return The {@link Command.Type} */ - boolean isDefaultEnabled(); + @Nonnull + Command.Type getType(); /** - * The {@link Command.Type} + * Gets the {@link DefaultMemberPermissions} of this command. + *
If no permissions have been set, this returns {@link DefaultMemberPermissions#ENABLED}. * - * @return The {@link Command.Type} + * @return DefaultMemberPermissions of this command. + * + * @see DefaultMemberPermissions#ENABLED + * @see DefaultMemberPermissions#DISABLED */ @Nonnull - Command.Type getType(); + DefaultMemberPermissions getDefaultPermissions(); + + /** + * Whether the command can only be used inside a guild. + *
Always true for guild commands. + * + * @return True, if this command is restricted to guilds. + */ + boolean isGuildOnly(); /** * Converts the provided {@link Command} into a CommandData instance. @@ -110,7 +131,8 @@ static CommandData fromCommand(@Nonnull Command command) Checks.notNull(command, "Command"); if (command.getType() != Command.Type.SLASH) return new CommandDataImpl(command.getType(), command.getName()) - .setDefaultEnabled(command.isDefaultEnabled()); + .setDefaultPermissions(command.getDefaultPermissions()) + .setGuildOnly(command.isGuildOnly()); return SlashCommandData.fromCommand(command); } @@ -139,7 +161,17 @@ static CommandData fromData(@Nonnull DataObject object) String name = object.getString("name"); Command.Type commandType = Command.Type.fromId(object.getInt("type", 1)); if (commandType != Command.Type.SLASH) - return new CommandDataImpl(commandType, name); + { + CommandData data = new CommandDataImpl(commandType, name); + if (!object.isNull("default_member_permissions")) + { + long defaultPermissions = object.getLong("default_member_permissions"); + data.setDefaultPermissions(defaultPermissions == 0 ? DefaultMemberPermissions.DISABLED : DefaultMemberPermissions.enabledFor(defaultPermissions)); + } + + data.setGuildOnly(!object.getBoolean("dm_permission", true)); + return data; + } return SlashCommandData.fromData(object); } diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/SlashCommandData.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/SlashCommandData.java index 0974d84461..92ba472092 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/SlashCommandData.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/SlashCommandData.java @@ -17,6 +17,7 @@ package net.dv8tion.jda.api.interactions.commands.build; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.utils.data.DataArray; @@ -39,7 +40,11 @@ public interface SlashCommandData extends CommandData @Nonnull @Override - SlashCommandData setDefaultEnabled(boolean enabled); + SlashCommandData setDefaultPermissions(@Nonnull DefaultMemberPermissions permission); + + @Nonnull + @Override + SlashCommandData setGuildOnly(boolean guildOnly); /** * Configure the description @@ -332,7 +337,8 @@ static SlashCommandData fromCommand(@Nonnull Command command) throw new IllegalArgumentException("Cannot convert command of type " + command.getType() + " to SlashCommandData!"); CommandDataImpl data = new CommandDataImpl(command.getName(), command.getDescription()); - data.setDefaultEnabled(command.isDefaultEnabled()); + data.setGuildOnly(command.isGuildOnly()); + data.setDefaultPermissions(command.getDefaultPermissions()); command.getOptions() .stream() .map(OptionData::fromOption) @@ -377,6 +383,14 @@ static SlashCommandData fromData(@Nonnull DataObject object) String description = object.getString("description"); DataArray options = object.optArray("options").orElseGet(DataArray::empty); CommandDataImpl command = new CommandDataImpl(name, description); + command.setGuildOnly(!object.getBoolean("dm_permission", true)); + + command.setDefaultPermissions( + object.isNull("default_member_permissions") + ? DefaultMemberPermissions.ENABLED + : DefaultMemberPermissions.enabledFor(object.getLong("default_member_permissions")) + ); + options.stream(DataArray::getObject).forEach(opt -> { OptionType type = OptionType.fromKey(opt.getInt("type")); diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/CommandPrivilege.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/CommandPrivilege.java deleted file mode 100644 index 820e7c7c92..0000000000 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/CommandPrivilege.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.dv8tion.jda.api.interactions.commands.privileges; - -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.ISnowflake; -import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.interactions.commands.Command; -import net.dv8tion.jda.api.interactions.commands.build.CommandData; -import net.dv8tion.jda.api.requests.restaction.CommandCreateAction; -import net.dv8tion.jda.api.utils.MiscUtil; -import net.dv8tion.jda.api.utils.data.DataObject; -import net.dv8tion.jda.api.utils.data.SerializableData; -import net.dv8tion.jda.internal.utils.Checks; - -import javax.annotation.Nonnull; -import java.util.Collection; -import java.util.Map; - -/** - * Privilege used to restrict access to a command within a {@link net.dv8tion.jda.api.entities.Guild Guild}. - * - *

If the command is {@link Command#isDefaultEnabled() enabled by default}, these can be used to blacklist users or roles from using the command. - * On the other hand if it is disabled by default, this can be used to whitelist users or roles instead. - * - * @see Guild#retrieveCommandPrivileges() - * @see Guild#updateCommandPrivilegesById(String, Collection) - * @see Guild#updateCommandPrivileges(Map) - * - * @see CommandData#setDefaultEnabled(boolean) - * @see CommandCreateAction#setDefaultEnabled(boolean) - * @see Command#isDefaultEnabled() - */ -public class CommandPrivilege implements ISnowflake, SerializableData -{ - private final Type type; - private final boolean enabled; - private final long id; - - public CommandPrivilege(@Nonnull Type type, boolean enabled, long id) - { - Checks.notNull(type, "Type"); - this.type = type; - this.enabled = enabled; - this.id = id; - } - - /** - * Creates a privilege that grants access to the command for the provided role. - * - * @param role - * The role to grant access to - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege enable(@Nonnull Role role) - { - Checks.notNull(role, "Role"); - return new CommandPrivilege(Type.ROLE, true, role.getIdLong()); - } - - /** - * Creates a privilege that grants access to the command for the provided user. - * - * @param user - * The user to grant access to - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege enable(@Nonnull User user) - { - Checks.notNull(user, "User"); - return new CommandPrivilege(Type.USER, true, user.getIdLong()); - } - - /** - * Creates a privilege that grants access to the command for the provided user. - * - * @param userId - * The user to grant access to - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege enableUser(@Nonnull String userId) - { - return enableUser(MiscUtil.parseSnowflake(userId)); - } - - /** - * Creates a privilege that grants access to the command for the provided user. - * - * @param userId - * The user to grant access to - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege enableUser(long userId) - { - return new CommandPrivilege(Type.USER, true, userId); - } - - /** - * Creates a privilege that grants access to the command for the provided role. - * - * @param roleId - * The role to grant access to - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege enableRole(@Nonnull String roleId) - { - return enableRole(MiscUtil.parseSnowflake(roleId)); - } - - /** - * Creates a privilege that grants access to the command for the provided role. - * - * @param roleId - * The role to grant access to - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege enableRole(long roleId) - { - return new CommandPrivilege(Type.ROLE, true, roleId); - } - - /** - * Creates a privilege that denies access to the command for the provided role. - * - * @param role - * The role to deny access for - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege disable(@Nonnull Role role) - { - Checks.notNull(role, "Role"); - return new CommandPrivilege(Type.ROLE, false, role.getIdLong()); - } - - /** - * Creates a privilege that denies access to the command for the provided user. - * - * @param user - * The user to grant denies for - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege disable(@Nonnull User user) - { - Checks.notNull(user, "User"); - return new CommandPrivilege(Type.USER, false, user.getIdLong()); - } - - /** - * Creates a privilege that denies access to the command for the provided user. - * - * @param userId - * The user to grant access for - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege disableUser(@Nonnull String userId) - { - return disableUser(MiscUtil.parseSnowflake(userId)); - } - - /** - * Creates a privilege that denies access to the command for the provided user. - * - * @param userId - * The user to grant access for - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege disableUser(long userId) - { - return new CommandPrivilege(Type.USER, false, userId); - } - - /** - * Creates a privilege that denies access to the command for the provided role. - * - * @param roleId - * The role to deny access for - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege disableRole(@Nonnull String roleId) - { - return disableRole(MiscUtil.parseSnowflake(roleId)); - } - - /** - * Creates a privilege that denies access to the command for the provided role. - * - * @param roleId - * The role to deny access for - * - * @return CommandPrivilege instance - */ - @Nonnull - public static CommandPrivilege disableRole(long roleId) - { - return new CommandPrivilege(Type.ROLE, false, roleId); - } - - - @Override - public long getIdLong() - { - return id; - } - - /** - * The {@link Type} of entity this privilege is applied to. - * - * @return The target {@link Type} - */ - @Nonnull - public Type getType() - { - return type; - } - - /** - * True if this privilege is granting access to the command - * - * @return Whether this privilege grants access - */ - public boolean isEnabled() - { - return enabled; - } - - /** - * True if this privilege is denying access to the command - * - * @return Whether this privilege denies access - */ - public boolean isDisabled() - { - return !enabled; - } - - @Override - public int hashCode() - { - return Long.hashCode(id); - } - - @Override - public boolean equals(Object obj) - { - if (obj == this) - return true; - if (!(obj instanceof CommandPrivilege)) - return false; - return ((CommandPrivilege) obj).id == id; - } - - @Nonnull - @Override - public DataObject toData() - { - return DataObject.empty() - .put("id", id) - .put("type", type.key) - .put("permission", enabled); - } - - /** - * The target type this privilege applies to. - */ - public enum Type - { - UNKNOWN(-1), - ROLE(1), - USER(2); - - private final int key; - - Type(int key) - { - this.key = key; - } - - /** - * Returns the appropriate enum constant for the given key. - * - * @param key - * The API key for the type - * - * @return The Type constant, or {@link #UNKNOWN} if there is no known representation - */ - @Nonnull - public static Type fromKey(int key) - { - for (Type type : values()) - { - if (type.key == key) - return type; - } - return UNKNOWN; - } - } -} diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/IntegrationPrivilege.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/IntegrationPrivilege.java new file mode 100644 index 0000000000..2c4c45dbb1 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/IntegrationPrivilege.java @@ -0,0 +1,177 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.interactions.commands.privileges; + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.ISnowflake; +import net.dv8tion.jda.internal.utils.Helpers; + +import javax.annotation.Nonnull; +import java.util.Objects; + +/** + * Privilege used to restrict access to a command within a {@link net.dv8tion.jda.api.entities.Guild Guild}. + * + *

Moderators of a Guild can create these privileges inside the Integrations Menu + * + * @see Guild#retrieveCommandPrivileges() + * @see net.dv8tion.jda.api.events.interaction.command.ApplicationCommandUpdatePrivilegesEvent + * @see net.dv8tion.jda.api.events.interaction.command.ApplicationUpdatePrivilegesEvent + */ +public class IntegrationPrivilege implements ISnowflake +{ + private final Guild guild; + private final Type type; + private final boolean enabled; + private final long id; + + public IntegrationPrivilege(@Nonnull Guild guild, @Nonnull Type type, boolean enabled, long id) + { + this.guild = guild; + this.type = type; + this.enabled = enabled; + this.id = id; + } + + /** + * Whether this IntegrationPrivilege targets the {@literal @everyone} Role + * + * @return True, if this IntegrationPrivilege targets the {@literal @everyone} Role + */ + public boolean targetsEveryone() + { + return type == Type.ROLE && id == guild.getIdLong(); + } + + /** + * Whether this IntegrationPrivilege targets "All channels" + * + * @return True, if this IntegrationPrivilege targets all channels + */ + public boolean targetsAllChannels() + { + return type == Type.CHANNEL && id == guild.getIdLong() - 1; + } + + @Override + public long getIdLong() + { + return id; + } + + /** + * The {@link Type} of entity this privilege is applied to. + * + * @return The target {@link Type} + */ + @Nonnull + public Type getType() + { + return type; + } + + /** + * The {@link Guild} this IntegrationPrivilege was created in. + * + * @return the guild in which this IntegrationPrivilege was created in. + */ + @Nonnull + public Guild getGuild() + { + return guild; + } + + /** + * True if this privilege is granting access to the command + * + * @return Whether this privilege grants access + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * True if this privilege is denying access to the command + * + * @return Whether this privilege denies access + */ + public boolean isDisabled() + { + return !enabled; + } + + @Override + public int hashCode() + { + return Objects.hash(id, enabled); + } + + @Override + public boolean equals(Object obj) + { + if (obj == this) + return true; + if (!(obj instanceof IntegrationPrivilege)) + return false; + IntegrationPrivilege other = (IntegrationPrivilege) obj; + return other.id == id && other.enabled == enabled; + } + + @Override + public String toString() + { + return Helpers.format("IntegrationPrivilege[%s](%s, enabled=%s)", type, id, enabled); + } + + /** + * The target type this privilege applies to. + */ + public enum Type + { + UNKNOWN(-1), + ROLE(1), + USER(2), + CHANNEL(3); + + private final int key; + + Type(int key) + { + this.key = key; + } + + /** + * Returns the appropriate enum constant for the given key. + * + * @param key + * The API key for the type + * + * @return The Type constant, or {@link #UNKNOWN} if there is no known representation + */ + @Nonnull + public static Type fromKey(int key) + { + for (Type type : values()) + { + if (type.key == key) + return type; + } + return UNKNOWN; + } + } +} diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/PrivilegeTargetType.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/PrivilegeTargetType.java new file mode 100644 index 0000000000..e36b5aa527 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/privileges/PrivilegeTargetType.java @@ -0,0 +1,33 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.dv8tion.jda.api.interactions.commands.privileges; + +/** + * Targets of a {@link net.dv8tion.jda.api.events.interaction.command.GenericPrivilegeUpdateEvent GenericPrivilegeUpdateEvent} + */ +public enum PrivilegeTargetType +{ + /** + * Indicates that privileges have been updated on the application itself. + */ + INTEGRATION, + + /** + * Indicates that privileges have been updated on a command. + */ + COMMAND, +} diff --git a/src/main/java/net/dv8tion/jda/api/requests/restaction/CommandCreateAction.java b/src/main/java/net/dv8tion/jda/api/requests/restaction/CommandCreateAction.java index 6a240beeeb..7ae0bb86bd 100644 --- a/src/main/java/net/dv8tion/jda/api/requests/restaction/CommandCreateAction.java +++ b/src/main/java/net/dv8tion/jda/api/requests/restaction/CommandCreateAction.java @@ -17,6 +17,7 @@ package net.dv8tion.jda.api.requests.restaction; import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; @@ -57,11 +58,6 @@ public interface CommandCreateAction extends RestAction, SlashCommandDa @CheckReturnValue CommandCreateAction deadline(long timestamp); - @Nonnull - @Override - @CheckReturnValue - CommandCreateAction setDefaultEnabled(boolean enabled); - @Nonnull @Override @CheckReturnValue @@ -134,4 +130,14 @@ default CommandCreateAction addSubcommandGroups(@Nonnull Collection CommandEditAction apply(@Nonnull CommandData commandData); /** - * Whether this command is available to everyone by default. - *
If this is disabled, you need to explicitly whitelist users and roles per guild. + * Configure the name + * + * @param name + * The lowercase alphanumeric (with dash) name, 1-32 characters. Use null to keep the current name. * - * @param enabled - * True, if this command is enabled by default for everyone. (Default: true) + * @throws IllegalArgumentException + * If the name is not alphanumeric or not between 1-32 characters * * @return The CommandEditAction instance, for chaining */ @Nonnull @CheckReturnValue - CommandEditAction setDefaultEnabled(boolean enabled); + CommandEditAction setName(@Nullable String name); /** - * Configure the name + * Sets whether this command is only usable in a guild (Default: false). + *
This only has an effect if this command is registered globally. * - * @param name - * The lowercase alphanumeric (with dash) name, 1-32 characters. Use null to keep the current name. + * @param guildOnly + * Whether to restrict this command to guilds * - * @throws IllegalArgumentException - * If the name is not alphanumeric or not between 1-32 characters + * @return The CommandEditAction instance, for chaining + */ + @Nonnull + @CheckReturnValue + CommandEditAction setGuildOnly(boolean guildOnly); + + /** + * Sets the {@link net.dv8tion.jda.api.Permission Permissions} that a user must have in a specific channel to be able to use this command. + *
By default, everyone can use this command ({@link DefaultMemberPermissions#ENABLED}). Additionally, a command can be disabled for everyone but admins via {@link DefaultMemberPermissions#DISABLED}. + *

These configurations can be overwritten by moderators in each guild. See {@link Command#retrievePrivileges(net.dv8tion.jda.api.entities.Guild)} to get moderator defined overrides. + * + * @param permission + * {@link DefaultMemberPermissions} representing the default permissions of this command. * * @return The CommandEditAction instance, for chaining + * + * @see DefaultMemberPermissions#ENABLED + * @see DefaultMemberPermissions#DISABLED */ @Nonnull @CheckReturnValue - CommandEditAction setName(@Nullable String name); + CommandEditAction setDefaultPermissions(@Nonnull DefaultMemberPermissions permission); /** * Configure the description diff --git a/src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java index abfb2f5767..0cc0331ef8 100644 --- a/src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java @@ -33,8 +33,9 @@ import net.dv8tion.jda.api.exceptions.ParsingException; import net.dv8tion.jda.api.exceptions.PermissionException; import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.PrivilegeConfig; import net.dv8tion.jda.api.interactions.commands.build.CommandData; -import net.dv8tion.jda.api.interactions.commands.privileges.CommandPrivilege; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; import net.dv8tion.jda.api.managers.AudioManager; import net.dv8tion.jda.api.managers.GuildManager; import net.dv8tion.jda.api.managers.GuildStickerManager; @@ -272,74 +273,30 @@ public RestAction deleteCommandById(@Nonnull String commandId) @Nonnull @Override - public RestAction> retrieveCommandPrivilegesById(@Nonnull String commandId) + public RestAction> retrieveIntegrationPrivilegesById(@Nonnull String targetId) { - Checks.isSnowflake(commandId, "ID"); - Route.CompiledRoute route = Route.Interactions.GET_COMMAND_PERMISSIONS.compile(getJDA().getSelfUser().getApplicationId(), getId(), commandId); + Checks.isSnowflake(targetId, "ID"); + Route.CompiledRoute route = Route.Interactions.GET_COMMAND_PERMISSIONS.compile(getJDA().getSelfUser().getApplicationId(), getId(), targetId); return new RestActionImpl<>(getJDA(), route, (response, request) -> parsePrivilegesList(response.getObject())); } @Nonnull @Override - public RestAction>> retrieveCommandPrivileges() + public RestAction retrieveCommandPrivileges() { Route.CompiledRoute route = Route.Interactions.GET_ALL_COMMAND_PERMISSIONS.compile(getJDA().getSelfUser().getApplicationId(), getId()); return new RestActionImpl<>(getJDA(), route, (response, request) -> { - Map> privileges = new HashMap<>(); + Map> privileges = new HashMap<>(); response.getArray().stream(DataArray::getObject).forEach(obj -> { String id = obj.getString("id"); - List list = parsePrivilegesList(obj); + List list = Collections.unmodifiableList(parsePrivilegesList(obj)); privileges.put(id, list); }); - return privileges; + return new PrivilegeConfig(this, privileges); }); } - @Nonnull - @Override - public RestAction> updateCommandPrivilegesById(@Nonnull String id, @Nonnull Collection privileges) - { - Checks.isSnowflake(id, "ID"); - Checks.noneNull(privileges, "Privileges"); - Checks.check(privileges.size() <= 10, "Cannot have more than 10 privileges for a command!"); - Route.CompiledRoute route = Route.Interactions.EDIT_COMMAND_PERMISSIONS.compile(getJDA().getSelfUser().getApplicationId(), getId(), id); - DataArray array = DataArray.fromCollection(privileges); - return new RestActionImpl<>(getJDA(), route, DataObject.empty().put("permissions", array), - (response, request) -> parsePrivilegesList(response.getObject())); - } - - @Nonnull - @Override - @SuppressWarnings("deprecation") - public RestAction>> updateCommandPrivileges(@Nonnull Map> privileges) - { - Checks.notNull(privileges, "Privileges"); - privileges.forEach((key, value) -> { - Checks.isSnowflake(key, "Map Key"); - Checks.noneNull(value, "Privilege List for Command"); - Checks.check(value.size() <= 10, "Cannot have more than 10 privileges for a command!"); - }); - DataArray array = DataArray.empty(); - privileges.forEach((commandId, list) -> { - DataObject entry = DataObject.empty(); - entry.put("id", commandId); - entry.put("permissions", DataArray.fromCollection(list)); - array.add(entry); - }); - - Route.CompiledRoute route = Route.Interactions.EDIT_ALL_COMMAND_PERMISSIONS.compile(getJDA().getSelfUser().getApplicationId(), getId()); - return new RestActionImpl<>(getJDA(), route, RequestBody.create(Requester.MEDIA_TYPE_JSON, array.toJson()), (response, request) -> { - Map> map = new HashMap<>(); - response.getArray().stream(DataArray::getObject).forEach(obj -> { - String id = obj.getString("id"); - List list = parsePrivilegesList(obj); - map.put(id, list); - }); - return map; - }); - } - - private List parsePrivilegesList(DataObject obj) + private List parsePrivilegesList(DataObject obj) { return obj.getArray("permissions") .stream(DataArray::getObject) @@ -347,11 +304,11 @@ private List parsePrivilegesList(DataObject obj) .collect(Collectors.toList()); } - private CommandPrivilege parsePrivilege(DataObject data) + private IntegrationPrivilege parsePrivilege(DataObject data) { - CommandPrivilege.Type type = CommandPrivilege.Type.fromKey(data.getInt("type", 1)); + IntegrationPrivilege.Type type = IntegrationPrivilege.Type.fromKey(data.getInt("type", 1)); boolean enabled = data.getBoolean("permission"); - return new CommandPrivilege(type, enabled, data.getUnsignedLong("id")); + return new IntegrationPrivilege(this, type, enabled, data.getUnsignedLong("id")); } @Nonnull diff --git a/src/main/java/net/dv8tion/jda/internal/handle/ApplicationCommandPermissionsUpdateHandler.java b/src/main/java/net/dv8tion/jda/internal/handle/ApplicationCommandPermissionsUpdateHandler.java new file mode 100644 index 0000000000..ff7352c0c7 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/internal/handle/ApplicationCommandPermissionsUpdateHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.dv8tion.jda.internal.handle; + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.interaction.command.ApplicationCommandUpdatePrivilegesEvent; +import net.dv8tion.jda.api.events.interaction.command.ApplicationUpdatePrivilegesEvent; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; +import net.dv8tion.jda.api.utils.data.DataArray; +import net.dv8tion.jda.api.utils.data.DataObject; +import net.dv8tion.jda.internal.JDAImpl; +import net.dv8tion.jda.internal.requests.WebSocketClient; + +import java.util.List; +import java.util.stream.Collectors; + +public class ApplicationCommandPermissionsUpdateHandler extends SocketHandler +{ + public ApplicationCommandPermissionsUpdateHandler(JDAImpl api) + { + super(api); + } + + @Override + protected Long handleInternally(DataObject content) + { + Guild guild; + if (!content.isNull("guild_id")) + { + long guildId = content.getUnsignedLong("guild_id"); + guild = getJDA().getGuildById(guildId); + if (getJDA().getGuildSetupController().isLocked(guildId)) + return guildId; + else if (guild == null) + { + WebSocketClient.LOG.debug("Received APPLICATION_COMMAND_PERMISSIONS_UPDATE for a guild that is not cached: GuildID: {}", guildId); + return null; + } + } + else + { + return null; + } + + long id = content.getUnsignedLong("id"); + long applicationId = content.getUnsignedLong("application_id"); + + List privileges = content.getArray("permissions") + .stream(DataArray::getObject) + .map(obj -> new IntegrationPrivilege(guild, IntegrationPrivilege.Type.fromKey(obj.getInt("type")), + obj.getBoolean("permission"), obj.getUnsignedLong("id"))) + .collect(Collectors.toList()); + + if (id != applicationId) + api.handleEvent(new ApplicationCommandUpdatePrivilegesEvent(api, responseNumber, guild, id, applicationId, privileges)); + else + api.handleEvent(new ApplicationUpdatePrivilegesEvent(api, responseNumber, guild, applicationId, privileges)); + return null; + } +} diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/CommandDataImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/CommandDataImpl.java index 18f3453c58..cea1e6a568 100644 --- a/src/main/java/net/dv8tion/jda/internal/interactions/CommandDataImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/interactions/CommandDataImpl.java @@ -16,6 +16,7 @@ package net.dv8tion.jda.internal.interactions; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; @@ -40,8 +41,9 @@ public class CommandDataImpl implements SlashCommandData private boolean allowSubcommands = true; private boolean allowGroups = true; private boolean allowOption = true; - private boolean defaultPermissions = true; // whether the command uses default_permissions (blacklist/whitelist) private boolean allowRequired = true; + private boolean guildOnly = false; + private DefaultMemberPermissions defaultMemberPermissions = DefaultMemberPermissions.ENABLED; private final Command.Type type; @@ -71,10 +73,13 @@ protected void checkType(Command.Type required, String action) public DataObject toData() { DataObject json = DataObject.empty() - .put("default_permission", defaultPermissions) .put("type", type.getId()) .put("name", name) - .put("options", options); + .put("options", options) + .put("dm_permission", !guildOnly) + .put("default_member_permissions", defaultMemberPermissions == DefaultMemberPermissions.ENABLED + ? null + : Long.toUnsignedString(defaultMemberPermissions.getPermissionsRaw())); if (type == Command.Type.SLASH) json.put("description", description); return json; @@ -87,6 +92,19 @@ public Command.Type getType() return type; } + @Nonnull + @Override + public DefaultMemberPermissions getDefaultPermissions() + { + return defaultMemberPermissions; + } + + @Override + public boolean isGuildOnly() + { + return guildOnly; + } + @Nonnull @Override public List getSubcommands() @@ -117,16 +135,19 @@ public List getSubcommandGroups() @Nonnull @Override - public CommandDataImpl setDefaultEnabled(boolean enabled) + public CommandDataImpl setDefaultPermissions(@Nonnull DefaultMemberPermissions permissions) { - this.defaultPermissions = enabled; + Checks.notNull(permissions, "Permissions"); + this.defaultMemberPermissions = permissions; return this; } + @Nonnull @Override - public boolean isDefaultEnabled() + public CommandDataImpl setGuildOnly(boolean guildOnly) { - return defaultPermissions; + this.guildOnly = guildOnly; + return this; } @Nonnull diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/command/CommandImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/command/CommandImpl.java index a63a84c57a..e0e17805d1 100644 --- a/src/main/java/net/dv8tion/jda/internal/interactions/command/CommandImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/interactions/command/CommandImpl.java @@ -18,9 +18,10 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionType; -import net.dv8tion.jda.api.interactions.commands.privileges.CommandPrivilege; +import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.CommandEditAction; import net.dv8tion.jda.api.utils.data.DataArray; @@ -51,8 +52,9 @@ public class CommandImpl implements Command private final List groups; private final List subcommands; private final long id, guildId, applicationId, version; - private final boolean defaultEnabled; + private final boolean guildOnly; private final Command.Type type; + private final DefaultMemberPermissions defaultMemberPermissions; public CommandImpl(JDAImpl api, Guild guild, DataObject json) { @@ -62,13 +64,18 @@ public CommandImpl(JDAImpl api, Guild guild, DataObject json) this.description = json.getString("description", ""); this.type = Command.Type.fromId(json.getInt("type", 1)); this.id = json.getUnsignedLong("id"); - this.defaultEnabled = json.getBoolean("default_permission"); this.guildId = guild != null ? guild.getIdLong() : 0L; this.applicationId = json.getUnsignedLong("application_id", api.getSelfUser().getApplicationIdLong()); this.options = parseOptions(json, OPTION_TEST, Command.Option::new); this.groups = parseOptions(json, GROUP_TEST, Command.SubcommandGroup::new); this.subcommands = parseOptions(json, SUBCOMMAND_TEST, Command.Subcommand::new); this.version = json.getUnsignedLong("version", id); + + this.defaultMemberPermissions = json.isNull("default_member_permissions") + ? DefaultMemberPermissions.ENABLED + : DefaultMemberPermissions.enabledFor(json.getLong("default_member_permissions")); + + this.guildOnly = !json.getBoolean("dm_permission", true); } public static List parseOptions(DataObject json, Predicate test, Function transform) @@ -105,28 +112,11 @@ public CommandEditAction editCommand() @Nonnull @Override - public RestAction> retrievePrivileges(@Nonnull Guild guild) + public RestAction> retrievePrivileges(@Nonnull Guild guild) { checkSelfUser("Cannot retrieve privileges for a command from another bot!"); Checks.notNull(guild, "Guild"); - return guild.retrieveCommandPrivilegesById(id); - } - - @Nonnull - @Override - public RestAction> updatePrivileges(@Nonnull Guild guild, @Nonnull Collection privileges) - { - checkSelfUser("Cannot update privileges for a command from another bot!"); - Checks.notNull(guild, "Guild"); - return guild.updateCommandPrivilegesById(id, privileges); - } - - @Nonnull - @Override - public RestAction> updatePrivileges(@Nonnull Guild guild, @Nonnull CommandPrivilege... privileges) - { - Checks.noneNull(privileges, "CommandPrivileges"); - return updatePrivileges(guild, Arrays.asList(privileges)); + return guild.retrieveIntegrationPrivilegesById(id); } @Nonnull @@ -157,12 +147,6 @@ public String getDescription() return description; } - @Override - public boolean isDefaultEnabled() - { - return defaultEnabled; - } - @Nonnull @Override public List getOptions() @@ -196,6 +180,19 @@ public long getVersion() return version; } + @Nonnull + @Override + public DefaultMemberPermissions getDefaultPermissions() + { + return defaultMemberPermissions; + } + + @Override + public boolean isGuildOnly() + { + return guildOnly; + } + @Override public long getIdLong() { diff --git a/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java b/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java index 0fd3830f5a..3d21ca0ff4 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java @@ -1319,51 +1319,52 @@ public T getHandler(String type) protected void setupHandlers() { - final SocketHandler.NOPHandler nopHandler = new SocketHandler.NOPHandler(api); - handlers.put("CHANNEL_CREATE", new ChannelCreateHandler(api)); - handlers.put("CHANNEL_DELETE", new ChannelDeleteHandler(api)); - handlers.put("CHANNEL_UPDATE", new ChannelUpdateHandler(api)); - handlers.put("GUILD_BAN_ADD", new GuildBanHandler(api, true)); - handlers.put("GUILD_BAN_REMOVE", new GuildBanHandler(api, false)); - handlers.put("GUILD_CREATE", new GuildCreateHandler(api)); - handlers.put("GUILD_DELETE", new GuildDeleteHandler(api)); - handlers.put("GUILD_EMOJIS_UPDATE", new GuildEmojisUpdateHandler(api)); - handlers.put("GUILD_MEMBER_ADD", new GuildMemberAddHandler(api)); - handlers.put("GUILD_MEMBER_REMOVE", new GuildMemberRemoveHandler(api)); - handlers.put("GUILD_MEMBER_UPDATE", new GuildMemberUpdateHandler(api)); - handlers.put("GUILD_MEMBERS_CHUNK", new GuildMembersChunkHandler(api)); - handlers.put("GUILD_ROLE_CREATE", new GuildRoleCreateHandler(api)); - handlers.put("GUILD_ROLE_DELETE", new GuildRoleDeleteHandler(api)); - handlers.put("GUILD_ROLE_UPDATE", new GuildRoleUpdateHandler(api)); - handlers.put("GUILD_SYNC", new GuildSyncHandler(api)); - handlers.put("GUILD_STICKERS_UPDATE", new GuildStickersUpdateHandler(api)); - handlers.put("GUILD_UPDATE", new GuildUpdateHandler(api)); - handlers.put("INTERACTION_CREATE", new InteractionCreateHandler(api)); - handlers.put("INVITE_CREATE", new InviteCreateHandler(api)); - handlers.put("INVITE_DELETE", new InviteDeleteHandler(api)); - handlers.put("MESSAGE_CREATE", new MessageCreateHandler(api)); - handlers.put("MESSAGE_DELETE", new MessageDeleteHandler(api)); - handlers.put("MESSAGE_DELETE_BULK", new MessageBulkDeleteHandler(api)); - handlers.put("MESSAGE_REACTION_ADD", new MessageReactionHandler(api, true)); - handlers.put("MESSAGE_REACTION_REMOVE", new MessageReactionHandler(api, false)); - handlers.put("MESSAGE_REACTION_REMOVE_ALL", new MessageReactionBulkRemoveHandler(api)); - handlers.put("MESSAGE_REACTION_REMOVE_EMOJI", new MessageReactionClearEmojiHandler(api)); - handlers.put("MESSAGE_UPDATE", new MessageUpdateHandler(api)); - handlers.put("READY", new ReadyHandler(api)); - handlers.put("STAGE_INSTANCE_CREATE", new StageInstanceCreateHandler(api)); - handlers.put("STAGE_INSTANCE_DELETE", new StageInstanceDeleteHandler(api)); - handlers.put("STAGE_INSTANCE_UPDATE", new StageInstanceUpdateHandler(api)); - handlers.put("THREAD_CREATE", new ThreadCreateHandler(api)); - handlers.put("THREAD_DELETE", new ThreadDeleteHandler(api)); - handlers.put("THREAD_LIST_SYNC", new ThreadListSyncHandler(api)); - handlers.put("THREAD_MEMBERS_UPDATE", new ThreadMembersUpdateHandler(api)); - handlers.put("THREAD_MEMBER_UPDATE", new ThreadMemberUpdateHandler(api)); - handlers.put("THREAD_UPDATE", new ThreadUpdateHandler(api)); - handlers.put("USER_UPDATE", new UserUpdateHandler(api)); - handlers.put("VOICE_SERVER_UPDATE", new VoiceServerUpdateHandler(api)); - handlers.put("VOICE_STATE_UPDATE", new VoiceStateUpdateHandler(api)); - handlers.put("PRESENCE_UPDATE", new PresenceUpdateHandler(api)); - handlers.put("TYPING_START", new TypingStartHandler(api)); + final SocketHandler.NOPHandler nopHandler = new SocketHandler.NOPHandler(api); + handlers.put("APPLICATION_COMMAND_PERMISSIONS_UPDATE", new ApplicationCommandPermissionsUpdateHandler(api)); + handlers.put("CHANNEL_CREATE", new ChannelCreateHandler(api)); + handlers.put("CHANNEL_DELETE", new ChannelDeleteHandler(api)); + handlers.put("CHANNEL_UPDATE", new ChannelUpdateHandler(api)); + handlers.put("GUILD_BAN_ADD", new GuildBanHandler(api, true)); + handlers.put("GUILD_BAN_REMOVE", new GuildBanHandler(api, false)); + handlers.put("GUILD_CREATE", new GuildCreateHandler(api)); + handlers.put("GUILD_DELETE", new GuildDeleteHandler(api)); + handlers.put("GUILD_EMOJIS_UPDATE", new GuildEmojisUpdateHandler(api)); + handlers.put("GUILD_MEMBER_ADD", new GuildMemberAddHandler(api)); + handlers.put("GUILD_MEMBER_REMOVE", new GuildMemberRemoveHandler(api)); + handlers.put("GUILD_MEMBER_UPDATE", new GuildMemberUpdateHandler(api)); + handlers.put("GUILD_MEMBERS_CHUNK", new GuildMembersChunkHandler(api)); + handlers.put("GUILD_ROLE_CREATE", new GuildRoleCreateHandler(api)); + handlers.put("GUILD_ROLE_DELETE", new GuildRoleDeleteHandler(api)); + handlers.put("GUILD_ROLE_UPDATE", new GuildRoleUpdateHandler(api)); + handlers.put("GUILD_SYNC", new GuildSyncHandler(api)); + handlers.put("GUILD_STICKERS_UPDATE", new GuildStickersUpdateHandler(api)); + handlers.put("GUILD_UPDATE", new GuildUpdateHandler(api)); + handlers.put("INTERACTION_CREATE", new InteractionCreateHandler(api)); + handlers.put("INVITE_CREATE", new InviteCreateHandler(api)); + handlers.put("INVITE_DELETE", new InviteDeleteHandler(api)); + handlers.put("MESSAGE_CREATE", new MessageCreateHandler(api)); + handlers.put("MESSAGE_DELETE", new MessageDeleteHandler(api)); + handlers.put("MESSAGE_DELETE_BULK", new MessageBulkDeleteHandler(api)); + handlers.put("MESSAGE_REACTION_ADD", new MessageReactionHandler(api, true)); + handlers.put("MESSAGE_REACTION_REMOVE", new MessageReactionHandler(api, false)); + handlers.put("MESSAGE_REACTION_REMOVE_ALL", new MessageReactionBulkRemoveHandler(api)); + handlers.put("MESSAGE_REACTION_REMOVE_EMOJI", new MessageReactionClearEmojiHandler(api)); + handlers.put("MESSAGE_UPDATE", new MessageUpdateHandler(api)); + handlers.put("PRESENCE_UPDATE", new PresenceUpdateHandler(api)); + handlers.put("READY", new ReadyHandler(api)); + handlers.put("STAGE_INSTANCE_CREATE", new StageInstanceCreateHandler(api)); + handlers.put("STAGE_INSTANCE_DELETE", new StageInstanceDeleteHandler(api)); + handlers.put("STAGE_INSTANCE_UPDATE", new StageInstanceUpdateHandler(api)); + handlers.put("THREAD_CREATE", new ThreadCreateHandler(api)); + handlers.put("THREAD_DELETE", new ThreadDeleteHandler(api)); + handlers.put("THREAD_LIST_SYNC", new ThreadListSyncHandler(api)); + handlers.put("THREAD_MEMBERS_UPDATE", new ThreadMembersUpdateHandler(api)); + handlers.put("THREAD_MEMBER_UPDATE", new ThreadMemberUpdateHandler(api)); + handlers.put("THREAD_UPDATE", new ThreadUpdateHandler(api)); + handlers.put("TYPING_START", new TypingStartHandler(api)); + handlers.put("USER_UPDATE", new UserUpdateHandler(api)); + handlers.put("VOICE_SERVER_UPDATE", new VoiceServerUpdateHandler(api)); + handlers.put("VOICE_STATE_UPDATE", new VoiceStateUpdateHandler(api)); // Unused events handlers.put("CHANNEL_PINS_ACK", nopHandler); diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/CommandCreateActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/CommandCreateActionImpl.java index 89500fc9b6..c404683b34 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/CommandCreateActionImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/CommandCreateActionImpl.java @@ -16,6 +16,7 @@ package net.dv8tion.jda.internal.requests.restaction; import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; @@ -79,23 +80,25 @@ public CommandCreateAction deadline(long timestamp) @Nonnull @Override - public CommandCreateAction setDefaultEnabled(boolean enabled) + public CommandCreateAction setDefaultPermissions(@Nonnull DefaultMemberPermissions permission) { - data.setDefaultEnabled(enabled); + data.setDefaultPermissions(permission); return this; } @Nonnull @Override - public String getName() + public CommandCreateAction setGuildOnly(boolean guildOnly) { - return data.getName(); + data.setGuildOnly(guildOnly); + return this; } + @Nonnull @Override - public boolean isDefaultEnabled() + public String getName() { - return data.isDefaultEnabled(); + return data.getName(); } @Nonnull @@ -105,6 +108,19 @@ public Command.Type getType() return data.getType(); } + @Nonnull + @Override + public DefaultMemberPermissions getDefaultPermissions() + { + return data.getDefaultPermissions(); + } + + @Override + public boolean isGuildOnly() + { + return data.isGuildOnly(); + } + @Nonnull @Override public CommandCreateAction timeout(long timeout, @Nonnull TimeUnit unit) diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/CommandEditActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/CommandEditActionImpl.java index c48ac1beb4..b01fff31bd 100644 --- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/CommandEditActionImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/CommandEditActionImpl.java @@ -19,6 +19,7 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; @@ -85,14 +86,6 @@ public CommandEditAction apply(@Nonnull CommandData commandData) return this; } - @Nonnull - @Override - public CommandEditAction setDefaultEnabled(boolean enabled) - { - data.setDefaultEnabled(enabled); - return this; - } - @Nonnull @Override public CommandEditAction addCheck(@Nonnull BooleanSupplier checks) @@ -121,6 +114,22 @@ public CommandEditAction setName(@Nullable String name) return this; } + @Nonnull + @Override + public CommandEditAction setGuildOnly(boolean guildOnly) + { + data.setGuildOnly(guildOnly); + return this; + } + + @Nonnull + @Override + public CommandEditAction setDefaultPermissions(@Nonnull DefaultMemberPermissions permission) + { + data.setDefaultPermissions(permission); + return this; + } + @Nonnull @Override public CommandEditAction setDescription(@Nullable String description) diff --git a/src/test/java/CommandDataTest.java b/src/test/java/CommandDataTest.java index 43eeea9463..5352c72047 100644 --- a/src/test/java/CommandDataTest.java +++ b/src/test/java/CommandDataTest.java @@ -14,7 +14,9 @@ * limitations under the License. */ +import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.OptionData; @@ -35,7 +37,8 @@ public class CommandDataTest public void testNormal() { CommandData command = new CommandDataImpl("ban", "Ban a user from this server") - .setDefaultEnabled(false) + .setGuildOnly(true) + .setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.BAN_MEMBERS)) .addOption(OptionType.USER, "user", "The user to ban", true) // required before non-required .addOption(OptionType.STRING, "reason", "The ban reason") // test that default is false .addOption(OptionType.INTEGER, "days", "The duration of the ban", false); // test with explicit false @@ -43,7 +46,8 @@ public void testNormal() DataObject data = command.toData(); Assertions.assertEquals("ban", data.getString("name")); Assertions.assertEquals("Ban a user from this server", data.getString("description")); - Assertions.assertFalse(data.getBoolean("default_permission")); + Assertions.assertFalse(data.getBoolean("dm_permission")); + Assertions.assertEquals(Permission.BAN_MEMBERS.getRawValue(), data.getUnsignedLong("default_member_permissions")); DataArray options = data.getArray("options"); @@ -63,11 +67,24 @@ public void testNormal() Assertions.assertEquals("The duration of the ban", option.getString("description")); } + @Test + public void testDefaultMemberPermissions() + { + CommandData command = new CommandDataImpl("ban", "Ban a user from this server") + .setDefaultPermissions(DefaultMemberPermissions.DISABLED); + DataObject data = command.toData(); + + Assertions.assertEquals(0, data.getUnsignedLong("default_member_permissions")); + + command.setDefaultPermissions(DefaultMemberPermissions.ENABLED); + data = command.toData(); + Assertions.assertTrue(data.isNull("default_member_permissions")); + } + @Test public void testSubcommand() { CommandDataImpl command = new CommandDataImpl("mod", "Moderation commands") - .setDefaultEnabled(true) .addSubcommands(new SubcommandData("ban", "Ban a user from this server") .addOption(OptionType.USER, "user", "The user to ban", true) // required before non-required .addOption(OptionType.STRING, "reason", "The ban reason") // test that default is false @@ -76,7 +93,6 @@ public void testSubcommand() DataObject data = command.toData(); Assertions.assertEquals("mod", data.getString("name")); Assertions.assertEquals("Moderation commands", data.getString("description")); - Assertions.assertTrue(data.getBoolean("default_permission")); DataObject subdata = data.getArray("options").getObject(0); Assertions.assertEquals("ban", subdata.getString("name")); @@ -113,7 +129,6 @@ public void testSubcommandGroup() DataObject data = command.toData(); Assertions.assertEquals("mod", data.getString("name")); Assertions.assertEquals("Moderation commands", data.getString("description")); - Assertions.assertTrue(data.getBoolean("default_permission")); DataObject group = data.getArray("options").getObject(0); Assertions.assertEquals("ban", group.getString("name"));