diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequireBotPermissionAttribute.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequireBotPermissionAttribute.cs
new file mode 100644
index 000000000..914978192
--- /dev/null
+++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequireBotPermissionAttribute.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Discord.Commands
+{
+ ///
+ /// This attribute requires that the bot has a speicifed permission in the channel a command is invoked in.
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+ public class RequireBotPermissionAttribute : PreconditionAttribute
+ {
+ public GuildPermission? GuildPermission { get; }
+ public ChannelPermission? ChannelPermission { get; }
+
+ ///
+ /// Require that the bot account has a specified GuildPermission
+ ///
+ /// This precondition will always fail if the command is being invoked in a private channel.
+ /// The GuildPermission that the bot must have. Multiple permissions can be specified by ORing or ANDing the permissions together.
+ public RequireBotPermissionAttribute(GuildPermission permission)
+ {
+ GuildPermission = permission;
+ ChannelPermission = null;
+ }
+ ///
+ /// Require that the bot account has a specified ChannelPermission.
+ ///
+ /// The ChannelPermission that the bot must have. Multiple permissions can be specified by ORing or ANDing the permissions together.
+ ///
+ ///
+ /// [Command("permission")]
+ /// [RequireBotPermission(ChannelPermission.ManageMessages)]
+ /// public async Task Purge()
+ /// {
+ /// }
+ ///
+ ///
+ public RequireBotPermissionAttribute(ChannelPermission permission)
+ {
+ ChannelPermission = permission;
+ GuildPermission = null;
+ }
+
+ public override async Task CheckPermissions(CommandContext context, CommandInfo command, IDependencyMap map)
+ {
+ var guildUser = await context.Guild.GetCurrentUserAsync();
+
+ if (GuildPermission.HasValue)
+ {
+ if (guildUser == null)
+ return PreconditionResult.FromError("Command must be used in a guild channel");
+ if (!guildUser.GuildPermissions.Has(GuildPermission.Value))
+ return PreconditionResult.FromError($"Command requires guild permission {GuildPermission.Value}");
+ }
+
+ if (ChannelPermission.HasValue)
+ {
+ var guildChannel = context.Channel as IGuildChannel;
+
+ ChannelPermissions perms;
+ if (guildChannel != null)
+ perms = guildUser.GetPermissions(guildChannel);
+ else
+ perms = ChannelPermissions.All(guildChannel);
+
+ if (!perms.Has(ChannelPermission.Value))
+ return PreconditionResult.FromError($"Command requires channel permission {ChannelPermission.Value}");
+ }
+
+ return PreconditionResult.FromSuccess();
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs
index 1cd32e72e..beadbbc89 100644
--- a/src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs
+++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequireContextAttribute.cs
@@ -11,11 +11,27 @@ namespace Discord.Commands
Group = 0x04
}
+ ///
+ /// Require that the command be invoked in a specified context.
+ ///
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class RequireContextAttribute : PreconditionAttribute
{
public ContextType Contexts { get; }
+ ///
+ /// Require that the command be invoked in a specified context.
+ ///
+ /// The type of context the command can be invoked in. Multiple contexts can be speicifed by ORing the contexts together.
+ ///
+ ///
+ /// [Command("private_only")]
+ /// [RequireContext(ContextType.DM | ContextType.Group)]
+ /// public async Task PrivateOnly()
+ /// {
+ /// }
+ ///
+ ///
public RequireContextAttribute(ContextType contexts)
{
Contexts = contexts;
diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequireOwnerAttribute.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequireOwnerAttribute.cs
new file mode 100644
index 000000000..8992cd115
--- /dev/null
+++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequireOwnerAttribute.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Discord;
+
+namespace Discord.Commands
+{
+ ///
+ /// Require that the command is invoked by the owner of the bot.
+ ///
+ /// This precondition will only work if the bot is a bot account.
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
+ public class RequireOwnerAttribute : PreconditionAttribute
+ {
+ public override async Task CheckPermissions(CommandContext context, CommandInfo command, IDependencyMap map)
+ {
+ var application = await context.Client.GetApplicationInfoAsync();
+ if (context.User.Id == application.Owner.Id) return PreconditionResult.FromSuccess();
+ return PreconditionResult.FromError("Command can only be run by the owner of the bot");
+ }
+ }
+}
diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequirePermissionAttribute.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs
similarity index 54%
rename from src/Discord.Net.Commands/Attributes/Preconditions/RequirePermissionAttribute.cs
rename to src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs
index 26aeac5ec..17cf234aa 100644
--- a/src/Discord.Net.Commands/Attributes/Preconditions/RequirePermissionAttribute.cs
+++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequireUserPermissionAttribute.cs
@@ -3,18 +3,40 @@ using System.Threading.Tasks;
namespace Discord.Commands
{
+ ///
+ /// This attribute requires that the user invoking the command has a specified permission.
+ ///
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
- public class RequirePermissionAttribute : PreconditionAttribute
+ public class RequireUserPermissionAttribute : PreconditionAttribute
{
public GuildPermission? GuildPermission { get; }
public ChannelPermission? ChannelPermission { get; }
- public RequirePermissionAttribute(GuildPermission permission)
+ ///
+ /// Require that the user invoking the command has a specified GuildPermission
+ ///
+ /// This precondition will always fail if the command is being invoked in a private channel.
+ /// The GuildPermission that the user must have. Multiple permissions can be specified by ORing or ANDing the permissions together.
+ public RequireUserPermissionAttribute(GuildPermission permission)
{
GuildPermission = permission;
ChannelPermission = null;
}
- public RequirePermissionAttribute(ChannelPermission permission)
+ ///
+ /// Require that the user invoking the command has a specified ChannelPermission.
+ ///
+ /// The ChannelPermission that the user must have. Multiple permissions can be specified by ORing or ANDing the permissions together.
+ ///
+ ///
+ /// [Command("permission")]
+ /// [RequireUserPermission(ChannelPermission.ReadMessageHistory & ChannelPermission.ReadMessages)]
+ /// public async Task HasPermission()
+ /// {
+ /// await ReplyAsync("You can read messages and the message history!");
+ /// }
+ ///
+ ///
+ public RequireUserPermissionAttribute(ChannelPermission permission)
{
ChannelPermission = permission;
GuildPermission = null;
diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
index 3eb4158d1..8c6a37f3c 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
@@ -38,6 +38,7 @@ namespace Discord.WebSocket
private int _nextAudioId;
private bool _canReconnect;
private DateTimeOffset? _statusSince;
+ private RestApplication _application;
/// Gets the shard of of this client.
public int ShardId { get; }
@@ -333,8 +334,10 @@ namespace Discord.WebSocket
}
///
- public Task GetApplicationInfoAsync()
- => ClientHelper.GetApplicationInfoAsync(this);
+ public async Task GetApplicationInfoAsync()
+ {
+ return _application ?? (_application = await ClientHelper.GetApplicationInfoAsync(this));
+ }
///
public SocketGuild GetGuild(ulong id)