diff --git a/src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs b/src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs index 834cf8162..d4a3b4a11 100644 --- a/src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; namespace Discord.Commands { + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true, Inherited = true)] public abstract class PreconditionAttribute : Attribute { public abstract Task CheckPermissions(IMessage context); diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequireDMAttribute.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequireDMAttribute.cs index ac621a602..eac63f66f 100644 --- a/src/Discord.Net.Commands/Attributes/Preconditions/RequireDMAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequireDMAttribute.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; namespace Discord.Commands { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class RequireDMAttribute : PreconditionAttribute { public override Task CheckPermissions(IMessage context) diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequireGuildAttribute.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequireGuildAttribute.cs index 58de17222..e909dc4f3 100644 --- a/src/Discord.Net.Commands/Attributes/Preconditions/RequireGuildAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequireGuildAttribute.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; namespace Discord.Commands { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class RequireGuildAttribute : PreconditionAttribute { public override Task CheckPermissions(IMessage context) diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequirePermission.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequirePermission.cs new file mode 100644 index 000000000..b88177818 --- /dev/null +++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequirePermission.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Discord.Commands.Attributes.Preconditions +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)] + public class RequirePermission : RequireGuildAttribute + { + public GuildPermission? GuildPermission { get; set; } + public ChannelPermission? ChannelPermission { get; set; } + + public RequirePermission(GuildPermission permission) + { + GuildPermission = permission; + ChannelPermission = null; + } + + public RequirePermission(ChannelPermission permission) + { + ChannelPermission = permission; + GuildPermission = null; + } + + public override async Task CheckPermissions(IMessage context) + { + var result = await base.CheckPermissions(context).ConfigureAwait(false); + + if (!result.IsSuccess) + return result; + + var author = context.Author as IGuildUser; + + if (GuildPermission.HasValue) + { + var guildPerms = author.GuildPermissions.ToList(); + if (!guildPerms.Contains(GuildPermission.Value)) + return PreconditionResult.FromError($"User is missing guild permission {GuildPermission.Value}"); + } + + if (ChannelPermission.HasValue) + { + var channel = context.Channel as IGuildChannel; + var channelPerms = author.GetPermissions(channel).ToList(); + + if (!channelPerms.Contains(ChannelPermission.Value)) + return PreconditionResult.FromError($"User is missing channel permission {ChannelPermission.Value}"); + } + + return PreconditionResult.FromSuccess(); + } + } +} diff --git a/src/Discord.Net.Commands/Attributes/Preconditions/RequireRoleAttribute.cs b/src/Discord.Net.Commands/Attributes/Preconditions/RequireRoleAttribute.cs index 7412315f3..4eda589c2 100644 --- a/src/Discord.Net.Commands/Attributes/Preconditions/RequireRoleAttribute.cs +++ b/src/Discord.Net.Commands/Attributes/Preconditions/RequireRoleAttribute.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; namespace Discord.Commands { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class RequireRoleAttribute : RequireGuildAttribute { public string Role { get; set; } diff --git a/src/Discord.Net.Commands/Command.cs b/src/Discord.Net.Commands/Command.cs index 482622d6a..e3b9367dc 100644 --- a/src/Discord.Net.Commands/Command.cs +++ b/src/Discord.Net.Commands/Command.cs @@ -44,9 +44,16 @@ namespace Discord.Commands public async Task CheckPreconditions(IMessage context) { - foreach (PreconditionAttribute permission in Preconditions) + foreach (PreconditionAttribute precondition in Module.Preconditions) { - var result = await permission.CheckPermissions(context).ConfigureAwait(false); + var result = await precondition.CheckPermissions(context).ConfigureAwait(false); + if (!result.IsSuccess) + return result; + } + + foreach (PreconditionAttribute precondition in Preconditions) + { + var result = await precondition.CheckPermissions(context).ConfigureAwait(false); if (!result.IsSuccess) return result; } diff --git a/src/Discord.Net.Commands/Module.cs b/src/Discord.Net.Commands/Module.cs index b884832bc..07feaeca2 100644 --- a/src/Discord.Net.Commands/Module.cs +++ b/src/Discord.Net.Commands/Module.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.Reflection; @@ -12,6 +13,8 @@ namespace Discord.Commands public IEnumerable Commands { get; } internal object Instance { get; } + public IReadOnlyList Preconditions { get; } + internal Module(CommandService service, object instance, ModuleAttribute moduleAttr, TypeInfo typeInfo) { Service = service; @@ -21,6 +24,8 @@ namespace Discord.Commands List commands = new List(); SearchClass(instance, commands, typeInfo, moduleAttr.Prefix ?? ""); Commands = commands; + + Preconditions = BuildPreconditions(typeInfo); } private void SearchClass(object instance, List commands, TypeInfo typeInfo, string groupPrefix) @@ -48,6 +53,11 @@ namespace Discord.Commands } } + private IReadOnlyList BuildPreconditions(TypeInfo typeInfo) + { + return typeInfo.GetCustomAttributes().ToImmutableArray(); + } + public override string ToString() => Name; private string DebuggerDisplay => Name; }