Skip to content

Commit

Permalink
feature: Allow setting custom error messages for preconditions (#1124)
Browse files Browse the repository at this point in the history
* Rebase and use in all in-box preconditions

* Silly git....

* Add configurable 'NotAGuild' message

* Respond to feedback
  • Loading branch information
Joe4evr authored and foxbot committed Dec 2, 2018
1 parent f4b1a5f commit 5677f23
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 10 deletions.
8 changes: 8 additions & 0 deletions src/Discord.Net.Commands/Attributes/PreconditionAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ public abstract class PreconditionAttribute : Attribute
/// </remarks>
public string Group { get; set; } = null;

/// <summary>
/// When overridden in a derived class, uses the supplied string
/// as the error message if the precondition doesn't pass.
/// Setting this for a class that doesn't override
/// this property is a no-op.
/// </summary>
public virtual string ErrorMessage { get { return null; } set { } }

/// <summary>
/// Checks if the <paramref name="command"/> has the sufficient permission to be executed.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class RequireBotPermissionAttribute : PreconditionAttribute
/// Gets the specified <see cref="Discord.ChannelPermission" /> of the precondition.
/// </summary>
public ChannelPermission? ChannelPermission { get; }
public override string ErrorMessage { get; set; }
public string NotAGuildErrorMessage { get; set; }

/// <summary>
/// Requires the bot account to have a specific <see cref="Discord.GuildPermission"/>.
Expand Down Expand Up @@ -56,9 +58,9 @@ public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandCon
if (GuildPermission.HasValue)
{
if (guildUser == null)
return PreconditionResult.FromError("Command must be used in a guild channel.");
return PreconditionResult.FromError(NotAGuildErrorMessage ?? "Command must be used in a guild channel.");
if (!guildUser.GuildPermissions.Has(GuildPermission.Value))
return PreconditionResult.FromError($"Bot requires guild permission {GuildPermission.Value}.");
return PreconditionResult.FromError(ErrorMessage ?? $"Bot requires guild permission {GuildPermission.Value}.");
}

if (ChannelPermission.HasValue)
Expand All @@ -70,7 +72,7 @@ public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandCon
perms = ChannelPermissions.All(context.Channel);

if (!perms.Has(ChannelPermission.Value))
return PreconditionResult.FromError($"Bot requires channel permission {ChannelPermission.Value}.");
return PreconditionResult.FromError(ErrorMessage ?? $"Bot requires channel permission {ChannelPermission.Value}.");
}

return PreconditionResult.FromSuccess();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class RequireContextAttribute : PreconditionAttribute
/// Gets the context required to execute the command.
/// </summary>
public ContextType Contexts { get; }
public override string ErrorMessage { get; set; }

/// <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>
Expand Down Expand Up @@ -66,7 +67,7 @@ public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext c
if (isValid)
return Task.FromResult(PreconditionResult.FromSuccess());
else
return Task.FromResult(PreconditionResult.FromError($"Invalid context for command; accepted contexts: {Contexts}."));
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"Invalid context for command; accepted contexts: {Contexts}."));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ namespace Discord.Commands
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class RequireNsfwAttribute : PreconditionAttribute
{
public override string ErrorMessage { get; set; }

/// <inheritdoc />
public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{
if (context.Channel is ITextChannel text && text.IsNsfw)
return Task.FromResult(PreconditionResult.FromSuccess());
else
return Task.FromResult(PreconditionResult.FromError("This command may only be invoked in an NSFW channel."));
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? "This command may only be invoked in an NSFW channel."));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ namespace Discord.Commands
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class RequireOwnerAttribute : PreconditionAttribute
{
public override string ErrorMessage { get; set; }

/// <inheritdoc />
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services)
{
Expand All @@ -42,10 +44,10 @@ public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandCon
case TokenType.Bot:
var application = await context.Client.GetApplicationInfoAsync().ConfigureAwait(false);
if (context.User.Id != application.Owner.Id)
return PreconditionResult.FromError("Command can only be run by the owner of the bot.");
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)}.");
return PreconditionResult.FromError($"{nameof(RequireOwnerAttribute)} is not supported by this {nameof(TokenType)}.");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class RequireUserPermissionAttribute : PreconditionAttribute
/// Gets the specified <see cref="Discord.ChannelPermission" /> of the precondition.
/// </summary>
public ChannelPermission? ChannelPermission { get; }
public override string ErrorMessage { get; set; }
public string NotAGuildErrorMessage { get; set; }

/// <summary>
/// Requires that the user invoking the command to have a specific <see cref="Discord.GuildPermission"/>.
Expand Down Expand Up @@ -54,9 +56,9 @@ public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext c
if (GuildPermission.HasValue)
{
if (guildUser == null)
return Task.FromResult(PreconditionResult.FromError("Command must be used in a guild channel."));
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($"User requires guild permission {GuildPermission.Value}."));
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"User requires guild permission {GuildPermission.Value}."));
}

if (ChannelPermission.HasValue)
Expand All @@ -68,7 +70,7 @@ public override Task<PreconditionResult> CheckPermissionsAsync(ICommandContext c
perms = ChannelPermissions.All(context.Channel);

if (!perms.Has(ChannelPermission.Value))
return Task.FromResult(PreconditionResult.FromError($"User requires channel permission {ChannelPermission.Value}."));
return Task.FromResult(PreconditionResult.FromError(ErrorMessage ?? $"User requires channel permission {ChannelPermission.Value}."));
}

return Task.FromResult(PreconditionResult.FromSuccess());
Expand Down

0 comments on commit 5677f23

Please sign in to comment.