diff --git a/docs/articles/commands/custom_context_checks.md b/docs/articles/commands/custom_context_checks.md index 52f5b36de..f6ff8e889 100644 --- a/docs/articles/commands/custom_context_checks.md +++ b/docs/articles/commands/custom_context_checks.md @@ -10,8 +10,8 @@ A context check contains two important pieces: - The attribute that will be applied to the command. This contains parameters that will be passed to the executing check. - The check itself. This is the method that determines if the command can be executed. -## Implementing a Context Check Attribute -To create a context check, you will need to create a new attribute that inherits from `CheckBaseAttribute`. This attribute will be applied to the command method and will contain the parameters that will be passed to the check method. +## Implementing a context check attribute +To create a context check, you will need to create a new attribute that inherits from `ContextCheckAttribute`. This attribute will be applied to the command method and may contain metadata for the check method to use. ```cs public class DirectMessageUsageAttribute : ContextCheckAttribute @@ -23,8 +23,11 @@ public class DirectMessageUsageAttribute : ContextCheckAttribute This is the attribute that you will apply to the command method. -## Implementing the Check Method -Now we're going to implement the logic which checks if the command is allowed to be executed. The `IContextCheck` interface is used to define the check method. The `T` is the attribute/parameters that's associated with the command. In this case, it's the `DirectMessageUsageAttribute`. +## Implementing the context check +Now we're going to implement the logic which checks if the command is allowed to be executed. The interface `IContextCheck` is used to define the check method. The `T` is the attribute that was applied to the command. In this case, it's the `DirectMessageUsageAttribute`, but it can be any check attribute - there can be multiple checks for one attribute. + +If the check was successful, the method should return `null`. If it was unsuccessful, the method should return a string that will then be provided +to `CommandsExtension.CommandErrored`. ```cs public class DirectMessageUsageCheck : IContextCheck @@ -59,7 +62,8 @@ public class DirectMessageUsageCheck : IContextCheck [!WARNING] +> Your check may inspect the command context to get more information, but it should not make any API calls, especially none that may alter state such as `RespondAsync`. This is an easy source of bugs, and depending on what you call you may stall an interaction over the three-second limit, which will break your interactions. Now, for the most important part, we need to register the check: @@ -73,4 +77,18 @@ Then we use the check like such: [Command("dm")] [DirectMessageUsage(DirectMessageUsage.RequireDMs)] public async ValueTask RequireDMs(CommandContext commandContext) => await commandContext.RespondAsync("This command was executed in a DM!"); -``` \ No newline at end of file +``` + +## Advanced Features + +The classes you use to implement checks participate in dependency injection, and you can request any type you previously supplied to the service provider in a public constructor. Useful applications include, but are not limited to, logging or tracking how often a command executes. + +A single check class can also implement multiple checks, like so: + +```cs +public class Check : IContextCheck, IContextCheck; +``` + +This means that all other code in that class can be shared between the two check methods, but this should be used with caution - it means that both checks are registered at once and cannot be removed independently of each other, and it means the same construction ceremony will run for both checks. + +There is no limit on how many different checks can reference the same attribute, they will all be supplied with that attribute. If you need a check that always runs, you can target `UnconditionalCheckAttribute`. \ No newline at end of file