[Feature] Parameter precondition attribute for simplifying performing hierarchical operations within a guild (#2906)
* Support interaction framework and update bundled preconditions docs * Support text commands and update bundled preconditions docs * Fix example * Move hierarchy util to `PermissionUtils` * Refactoring
This commit is contained in:
@@ -30,6 +30,7 @@ to use.
|
||||
* @Discord.Interactions.RequireNsfwAttribute
|
||||
* @Discord.Interactions.RequireRoleAttribute
|
||||
* @Discord.Interactions.RequireTeamAttribute
|
||||
* @Discord.Interactions.DoHierarchyCheckAttribute
|
||||
|
||||
## Using Preconditions
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ to use.
|
||||
* @Discord.Commands.RequireBotPermissionAttribute
|
||||
* @Discord.Commands.RequireUserPermissionAttribute
|
||||
* @Discord.Commands.RequireNsfwAttribute
|
||||
* @Discord.Commands.DoHierarchyCheckAttribute
|
||||
|
||||
## Using Preconditions
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures that command parameters are passed within a correct hierarchical context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Useful for performing hierarchical operations within a guild, such as managing roles or users.
|
||||
/// <note type="warning">
|
||||
/// This supports <see cref="IRole"/>, <see cref="IGuildUser"/>, and <see cref="IUser"/> parameter types.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the parameter type is not supported by this precondition attribute.
|
||||
/// </exception>
|
||||
/// <seealso cref="RequireBotPermissionAttribute"/>
|
||||
/// <seealso cref="RequireUserPermissionAttribute"/>
|
||||
public class DoHierarchyCheckAttribute : ParameterPreconditionAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the error message displayed when the command is used outside of a guild.
|
||||
/// </summary>
|
||||
public string NotAGuildErrorMessage { get; set; } = "This command cannot be used outside of a guild.";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the error message to be returned if execution context doesn't pass the precondition check.
|
||||
/// </summary>
|
||||
public string ErrorMessage { get; set; } = "You cannot target anyone who is higher or equal in the hierarchy to you or the bot.";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the parameter type is not supported by this precondition attribute.
|
||||
/// </exception>
|
||||
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context, ParameterInfo parameterInfo, object value, IServiceProvider services)
|
||||
{
|
||||
if (context.User is not IGuildUser guildUser)
|
||||
return PreconditionResult.FromError(NotAGuildErrorMessage);
|
||||
|
||||
var hieararchy = PermissionUtils.GetHieararchy(value);
|
||||
if (hieararchy >= guildUser.Hierarchy ||
|
||||
hieararchy >= (await context.Guild.GetCurrentUserAsync().ConfigureAwait(false)).Hierarchy)
|
||||
return PreconditionResult.FromError(ErrorMessage);
|
||||
|
||||
return PreconditionResult.FromSuccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/Discord.Net.Core/Utils/PermissionUtils.cs
Normal file
31
src/Discord.Net.Core/Utils/PermissionUtils.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a series of helper methods for permissions.
|
||||
/// </summary>
|
||||
public static class PermissionUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the hierarchy of a target object based on its type.
|
||||
/// </summary>
|
||||
/// <param name="target">
|
||||
/// The target object: <see cref="IRole"/>, <see cref="IGuildUser"/>, or <see cref="IUser"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// An integer representing the hierarchy of the target.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the parameter type is not supported by this precondition attribute.
|
||||
/// </exception>
|
||||
public static int GetHieararchy(object target) => target switch
|
||||
{
|
||||
// The order of cases here is important to determine the correct hierarchy value.
|
||||
IRole role => role.Position,
|
||||
IGuildUser guildUser => guildUser.Hierarchy,
|
||||
IUser => int.MinValue,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(target), "Cannot determine hierarchy for the provided target.")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Discord.Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures that command parameters are passed within a correct hierarchical context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Useful for performing hierarchical operations within a guild, such as managing roles or users.
|
||||
/// <note type="warning">
|
||||
/// This supports <see cref="IRole"/>, <see cref="IGuildUser"/>, and <see cref="IUser"/> parameter types.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the parameter type is not supported by this precondition attribute.
|
||||
/// </exception>
|
||||
/// <seealso cref="RequireRoleAttribute"/>
|
||||
/// <seealso cref="RequireBotPermissionAttribute"/>
|
||||
/// <seealso cref="RequireUserPermissionAttribute"/>
|
||||
public class DoHierarchyCheckAttribute : ParameterPreconditionAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the error message displayed when the command is used outside of a guild.
|
||||
/// </summary>
|
||||
public string NotAGuildErrorMessage { get; set; } = "This command cannot be used outside of a guild.";
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ErrorMessage => "You cannot target anyone who is higher or equal in the hierarchy to you or the bot.";
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// Thrown when the parameter type is not supported by this precondition attribute.
|
||||
/// </exception>
|
||||
public override async Task<PreconditionResult> CheckRequirementsAsync(IInteractionContext context, IParameterInfo parameterInfo, object value, IServiceProvider services)
|
||||
{
|
||||
if (context.User is not IGuildUser guildUser)
|
||||
return PreconditionResult.FromError(NotAGuildErrorMessage);
|
||||
|
||||
var hieararchy = PermissionUtils.GetHieararchy(value);
|
||||
if (hieararchy >= guildUser.Hierarchy ||
|
||||
hieararchy >= (await context.Guild.GetCurrentUserAsync().ConfigureAwait(false)).Hierarchy)
|
||||
return PreconditionResult.FromError(ErrorMessage);
|
||||
|
||||
return PreconditionResult.FromSuccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user