Update to Labs 3.5.0 (#1971)
* Merge https://github.com/Discord-Net-Labs/Discord.Net-Labs into patch/labs3.5.0 * Add missing periods
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires the bot to have a specific permission in the channel a command is invoked in.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class RequireBotPermissionAttribute : PreconditionAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the specified <see cref="Discord.GuildPermission" /> of the precondition.
|
||||
/// </summary>
|
||||
public GuildPermission? GuildPermission { get; }
|
||||
/// <summary>
|
||||
/// Gets the specified <see cref="Discord.ChannelPermission" /> of the precondition.
|
||||
/// </summary>
|
||||
public ChannelPermission? ChannelPermission { get; }
|
||||
/// <summary>
|
||||
/// Gets or sets the error message if the precondition
|
||||
/// fails due to being run outside of a Guild channel.
|
||||
/// </summary>
|
||||
public string NotAGuildErrorMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Requires the bot account to have a specific <see cref="Discord.GuildPermission"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This precondition will always fail if the command is being invoked in a <see cref="IPrivateChannel"/>.
|
||||
/// </remarks>
|
||||
/// <param name="permission">
|
||||
/// The <see cref="Discord.GuildPermission"/> that the bot must have. Multiple permissions can be specified
|
||||
/// by ORing the permissions together.
|
||||
/// </param>
|
||||
public RequireBotPermissionAttribute(GuildPermission permission)
|
||||
{
|
||||
GuildPermission = permission;
|
||||
ChannelPermission = null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Requires that the bot account to have a specific <see cref="Discord.ChannelPermission"/>.
|
||||
/// </summary>
|
||||
/// <param name="permission">
|
||||
/// The <see cref="Discord.ChannelPermission"/> that the bot must have. Multiple permissions can be
|
||||
/// specified by ORing the permissions together.
|
||||
/// </param>
|
||||
public RequireBotPermissionAttribute(ChannelPermission permission)
|
||||
{
|
||||
ChannelPermission = permission;
|
||||
GuildPermission = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo command, IServiceProvider services)
|
||||
{
|
||||
IGuildUser guildUser = null;
|
||||
if (context.Guild != null)
|
||||
guildUser = await context.Guild.GetCurrentUserAsync().ConfigureAwait(false);
|
||||
|
||||
if (GuildPermission.HasValue)
|
||||
{
|
||||
if (guildUser == null)
|
||||
return PreconditionResult.FromError(NotAGuildErrorMessage ?? "Command must be used in a guild channel.");
|
||||
if (!guildUser.GuildPermissions.Has(GuildPermission.Value))
|
||||
return PreconditionResult.FromError(ErrorMessage ?? $"Bot requires guild permission {GuildPermission.Value}.");
|
||||
}
|
||||
|
||||
if (ChannelPermission.HasValue)
|
||||
{
|
||||
ChannelPermissions perms;
|
||||
if (context.Channel is IGuildChannel guildChannel)
|
||||
perms = guildUser.GetPermissions(guildChannel);
|
||||
else
|
||||
perms = ChannelPermissions.All(context.Channel);
|
||||
|
||||
if (!perms.Has(ChannelPermission.Value))
|
||||
return PreconditionResult.FromError(ErrorMessage ?? $"Bot requires channel permission {ChannelPermission.Value}.");
|
||||
}
|
||||
|
||||
return PreconditionResult.FromSuccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the type of command context (i.e. where the command is being executed).
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum ContextType
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the command to be executed within a guild.
|
||||
/// </summary>
|
||||
Guild = 0x01,
|
||||
/// <summary>
|
||||
/// Specifies the command to be executed within a DM.
|
||||
/// </summary>
|
||||
DM = 0x02,
|
||||
/// <summary>
|
||||
/// Specifies the command to be executed within a group.
|
||||
/// </summary>
|
||||
Group = 0x04
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requires the command to be invoked in a specified context (e.g. in guild, DM).
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class RequireContextAttribute : PreconditionAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the context required to execute the command.
|
||||
/// </summary>
|
||||
public ContextType Contexts { get; }
|
||||
|
||||
/// <summary> Requires the command to be invoked in the specified context. </summary>
|
||||
/// <param name="contexts">The type of context the command can be invoked in. Multiple contexts can be specified by ORing the contexts together.</param>
|
||||
/// <example>
|
||||
/// <code language="cs">
|
||||
/// [Command("secret")]
|
||||
/// [RequireContext(ContextType.DM | ContextType.Group)]
|
||||
/// public Task PrivateOnlyAsync()
|
||||
/// {
|
||||
/// return ReplyAsync("shh, this command is a secret");
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public RequireContextAttribute(ContextType contexts)
|
||||
{
|
||||
Contexts = contexts;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo command, IServiceProvider services)
|
||||
{
|
||||
bool isValid = false;
|
||||
|
||||
if ((Contexts & ContextType.Guild) != 0)
|
||||
isValid = context.Channel is IGuildChannel;
|
||||
if ((Contexts & ContextType.DM) != 0)
|
||||
isValid = isValid || context.Channel is IDMChannel;
|
||||
if ((Contexts & ContextType.Group) != 0)
|
||||
isValid = isValid || context.Channel is IGroupChannel;
|
||||
|
||||
if (isValid)
|
||||
return Task.FromResult(PreconditionResult.FromSuccess());
|
||||
else
|
||||
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"Invalid context for command; accepted contexts: {Contexts}."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires the command to be invoked in a channel marked NSFW.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The precondition will restrict the access of the command or module to be accessed within a guild channel
|
||||
/// that has been marked as mature or NSFW. If the channel is not of type <see cref="ITextChannel"/> or the
|
||||
/// channel is not marked as NSFW, the precondition will fail with an erroneous <see cref="PreconditionResult"/>.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example restricts the command <c>too-cool</c> to an NSFW-enabled channel only.
|
||||
/// <code language="cs">
|
||||
/// public class DankModule : ModuleBase
|
||||
/// {
|
||||
/// [Command("cool")]
|
||||
/// public Task CoolAsync()
|
||||
/// => ReplyAsync("I'm cool for everyone.");
|
||||
///
|
||||
/// [RequireNsfw]
|
||||
/// [Command("too-cool")]
|
||||
/// public Task TooCoolAsync()
|
||||
/// => ReplyAsync("You can only see this if you're cool enough.");
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class RequireNsfwAttribute : PreconditionAttribute
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo command, IServiceProvider services)
|
||||
{
|
||||
if (context.Channel is ITextChannel text && text.IsNsfw)
|
||||
return Task.FromResult(PreconditionResult.FromSuccess());
|
||||
else
|
||||
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? "This command may only be invoked in an NSFW channel."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires the command to be invoked by the owner of the bot.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This precondition will restrict the access of the command or module to the owner of the Discord application.
|
||||
/// If the precondition fails to be met, an erroneous <see cref="PreconditionResult"/> will be returned with the
|
||||
/// message "Command can only be run by the owner of the bot."
|
||||
/// <note>
|
||||
/// This precondition will only work if the account has a <see cref="TokenType"/> of <see cref="TokenType.Bot"/>
|
||||
/// ;otherwise, this precondition will always fail.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class RequireOwnerAttribute : PreconditionAttribute
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override async Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo command, IServiceProvider services)
|
||||
{
|
||||
switch (context.Client.TokenType)
|
||||
{
|
||||
case TokenType.Bot:
|
||||
var application = await context.Client.GetApplicationInfoAsync().ConfigureAwait(false);
|
||||
if (context.User.Id != application.Owner.Id)
|
||||
return PreconditionResult.FromError(ErrorMessage ?? "Command can only be run by the owner of the bot.");
|
||||
return PreconditionResult.FromSuccess();
|
||||
default:
|
||||
return PreconditionResult.FromError($"{nameof(RequireOwnerAttribute)} is not supported by this {nameof(TokenType)}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires the user invoking the command to have a specified role.
|
||||
/// </summary>
|
||||
public class RequireRoleAttribute : PreconditionAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the specified Role name of the precondition.
|
||||
/// </summary>
|
||||
public string RoleName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified Role ID of the precondition.
|
||||
/// </summary>
|
||||
public ulong? RoleId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the error message if the precondition
|
||||
/// fails due to being run outside of a Guild channel.
|
||||
/// </summary>
|
||||
public string NotAGuildErrorMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Requires that the user invoking the command to have a specific Role.
|
||||
/// </summary>
|
||||
/// <param name="roleId">Id of the role that the user must have.</param>
|
||||
public RequireRoleAttribute(ulong roleId)
|
||||
{
|
||||
RoleId = roleId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requires that the user invoking the command to have a specific Role.
|
||||
/// </summary>
|
||||
/// <param name="roleName">Name of the role that the user must have.</param>
|
||||
public RequireRoleAttribute(string roleName)
|
||||
{
|
||||
RoleName = roleName;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services)
|
||||
{
|
||||
if (context.User is not IGuildUser guildUser)
|
||||
return Task.FromResult(PreconditionResult.FromError(NotAGuildErrorMessage ?? "Command must be used in a guild channel."));
|
||||
|
||||
if (RoleId.HasValue)
|
||||
{
|
||||
if (guildUser.RoleIds.Contains(RoleId.Value))
|
||||
return Task.FromResult(PreconditionResult.FromSuccess());
|
||||
else
|
||||
Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"User requires guild role {context.Guild.GetRole(RoleId.Value).Name}."));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(RoleName))
|
||||
{
|
||||
if (guildUser.Guild.Roles.Any(x => x.Name == RoleName))
|
||||
return Task.FromResult(PreconditionResult.FromSuccess());
|
||||
else
|
||||
Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"User requires guild role {RoleName}."));
|
||||
}
|
||||
|
||||
return Task.FromResult(PreconditionResult.FromSuccess());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Requires the user invoking the command to have a specified permission.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
|
||||
public class RequireUserPermissionAttribute : PreconditionAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the specified <see cref="Discord.GuildPermission" /> of the precondition.
|
||||
/// </summary>
|
||||
public GuildPermission? GuildPermission { get; }
|
||||
/// <summary>
|
||||
/// Gets the specified <see cref="Discord.ChannelPermission" /> of the precondition.
|
||||
/// </summary>
|
||||
public ChannelPermission? ChannelPermission { get; }
|
||||
/// <summary>
|
||||
/// Gets or sets the error message if the precondition
|
||||
/// fails due to being run outside of a Guild channel.
|
||||
/// </summary>
|
||||
public string NotAGuildErrorMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Requires that the user invoking the command to have a specific <see cref="Discord.GuildPermission"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This precondition will always fail if the command is being invoked in a <see cref="IPrivateChannel"/>.
|
||||
/// </remarks>
|
||||
/// <param name="permission">
|
||||
/// The <see cref="Discord.GuildPermission" /> that the user must have. Multiple permissions can be
|
||||
/// specified by ORing the permissions together.
|
||||
/// </param>
|
||||
public RequireUserPermissionAttribute(GuildPermission guildPermission)
|
||||
{
|
||||
GuildPermission = guildPermission;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Requires that the user invoking the command to have a specific <see cref="Discord.ChannelPermission"/>.
|
||||
/// </summary>
|
||||
/// <param name="permission">
|
||||
/// The <see cref="Discord.ChannelPermission"/> that the user must have. Multiple permissions can be
|
||||
/// specified by ORing the permissions together.
|
||||
/// </param>
|
||||
public RequireUserPermissionAttribute(ChannelPermission channelPermission)
|
||||
{
|
||||
ChannelPermission = channelPermission;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, ICommandInfo commandInfo, IServiceProvider services)
|
||||
{
|
||||
var guildUser = context.User as IGuildUser;
|
||||
|
||||
if (GuildPermission.HasValue)
|
||||
{
|
||||
if (guildUser == null)
|
||||
return Task.FromResult(PreconditionResult.FromError(NotAGuildErrorMessage ?? "Command must be used in a guild channel."));
|
||||
if (!guildUser.GuildPermissions.Has(GuildPermission.Value))
|
||||
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"User requires guild permission {GuildPermission.Value}."));
|
||||
}
|
||||
|
||||
if (ChannelPermission.HasValue)
|
||||
{
|
||||
ChannelPermissions perms;
|
||||
if (context.Channel is IGuildChannel guildChannel)
|
||||
perms = guildUser.GetPermissions(guildChannel);
|
||||
else
|
||||
perms = ChannelPermissions.All(context.Channel);
|
||||
|
||||
if (!perms.Has(ChannelPermission.Value))
|
||||
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"User requires channel permission {ChannelPermission.Value}."));
|
||||
}
|
||||
|
||||
return Task.FromResult(PreconditionResult.FromSuccess());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,11 @@ namespace Discord.Interactions
|
||||
{
|
||||
case RestAutocompleteInteraction restAutocomplete:
|
||||
var payload = restAutocomplete.Respond(result.Suggestions);
|
||||
await InteractionService._restResponseCallback(context, payload).ConfigureAwait(false);
|
||||
|
||||
if (context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null)
|
||||
await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false);
|
||||
else
|
||||
await InteractionService._restResponseCallback(context, payload).ConfigureAwait(false);
|
||||
break;
|
||||
case SocketAutocompleteInteraction socketAutocomplete:
|
||||
await socketAutocomplete.RespondAsync(result.Suggestions).ConfigureAwait(false);
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net6.0;net5.0;netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
<RootNamespace>Discord.Interactions</RootNamespace>
|
||||
<AssemblyName>Discord.Net.Interactions</AssemblyName>
|
||||
<PackageId>Discord.Net.Interactions</PackageId>
|
||||
<Description>A Discord.Net extension adding support for Application Commands.</Description>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -30,7 +30,12 @@ namespace Discord.Interactions
|
||||
if (Context.Interaction is not RestInteraction restInteraction)
|
||||
throw new InvalidOperationException($"Invalid interaction type. Interaction must be a type of {nameof(RestInteraction)} in order to execute this method");
|
||||
|
||||
await InteractionService._restResponseCallback(Context, restInteraction.Defer(ephemeral, options)).ConfigureAwait(false);
|
||||
var payload = restInteraction.Defer(ephemeral, options);
|
||||
|
||||
if (Context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null)
|
||||
await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false);
|
||||
else
|
||||
await InteractionService._restResponseCallback(Context, payload).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,7 +58,12 @@ namespace Discord.Interactions
|
||||
if (Context.Interaction is not RestInteraction restInteraction)
|
||||
throw new InvalidOperationException($"Invalid interaction type. Interaction must be a type of {nameof(RestInteraction)} in order to execute this method");
|
||||
|
||||
await InteractionService._restResponseCallback(Context, restInteraction.Respond(text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options)).ConfigureAwait(false);
|
||||
var payload = restInteraction.Respond(text, embeds, isTTS, ephemeral, allowedMentions, components, embed, options);
|
||||
|
||||
if (Context is IRestInteractionContext restContext && restContext.InteractionResponseCallback != null)
|
||||
await restContext.InteractionResponseCallback.Invoke(payload).ConfigureAwait(false);
|
||||
else
|
||||
await InteractionService._restResponseCallback(Context, payload).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user