问题描述
我正在尝试寻找一种方法来检查用户是否具有X角色,如果没有,则执行某些操作,类似于使用@H_404_1@[RequireUserPermission(GuildPermission.Administrator)]时如何将其记录到控制台中,只是我不知道。不想让它登录到控制台,例如:
@H_404_1@if (has role) { // do stuff } else { // do stuff }
我正在尝试将其实现的命令
@H_404_1@[Command("clear")] [RequireUserPermission(GuildPermission.ManageRoles)] public async Task Clear(int amount) { IEnumerable<IMessage> messages = await Context.Channel.GetMessagesAsync(amount + 1).FlattenAsync(); await ((ITextChannel)Context.Channel).DeleteMessagesAsync(messages); const int delay = 3000; IUserMessage m = await ReplyAsync($"I have deleted {amount} messages"); await Task.Delay(delay); await m.DeleteAsync(); Console.Write(amount + " was cleared in a channel"); }
解决方法
正如akac所指出的那样,您提到的前提条件[RequireUserPermission(...)]
检查分配给用户的任何角色是否授予他们执行特定任务的权限。考虑以下示例。您创建一个名为“主持人”的角色,并启用权限“管理消息”。然后,您将前提条件[RequireUserPermission(ChannelPermission.ManageMessages)]
添加到您的Clear()
方法中。您的Clear()
方法现在对具有“主持人”角色的任何人都有效,因为他们有权管理邮件。它还将允许具有相同许可权的任何其他角色的任何人使用它。
但是,如果以后您决定不希望“主持人”能够管理消息并删除该角色的权限,那么前提条件将自动阻止该角色中的任何人使用Clear
命令
如果您选中用户角色而不是其权限,则即使您已删除了从以下位置管理邮件的权限,具有“主持人”角色的用户仍可以使用Clear
命令删除邮件该角色。
如果您要检查角色而不使用前提条件检查其权限的唯一原因是因为您不希望它登录到控制台,那么这可能是错误的方法。相反,您应该考虑遵守前提条件,并查看如何处理日志记录以防止将该消息记录到控制台。
如果您仍然想检查用户的角色,那么下面是一个示例,说明如何使用提供的Clear()
方法执行此操作。您将需要在文件顶部添加using System.Linq;
,并在第二个"RoleName"
语句中将if
替换为您要检查的角色的名称。
public async Task Clear(int amount)
{
// Get the user that executed the command cast it to SocketGuildUser
// so we can access the Roles property
if (Context.User is SocketGuildUser user)
{
// Check if the user has the requried role
if (user.Roles.Any(r => r.Name == "RoleName"))
{
IEnumerable<IMessage> messages = await Context.Channel.GetMessagesAsync(amount + 1).FlattenAsync();
await((ITextChannel) Context.Channel).DeleteMessagesAsync(messages);
const int delay = 3000;
IUserMessage m = await ReplyAsync($"I have deleted {amount} messages");
await Task.Delay(delay);
await m.DeleteAsync();
Console.Write(amount + " was cleared in a channel");
}
else
{
await Context.Channel.SendMessageAsync("Sorry,you don't have permission to do that.");
}
}
}
,
几天前我遇到了这个问题,我的解决方案是创建一个自Discord.Commands.PreconditionAttribute
继承的自定义属性
我在Visual Studio安装中使用dotPeek进行反编译并阅读了命令服务的实际工作原理时发现了这一点,因为我想知道它们的属性也是如此。在命令服务执行命令的一部分中,它检查每个命令的所有前提条件,只有在满足每个条件时,它才执行功能。
此类具有名为CheckPermissionsAsync
以下是适合您的示例:
public class RequiresRoleAttribute : PreconditionAttribute
{
private string m_role;
public RequiresRoleAttribute (string role)
{
m_role = role;
}
public override async Task<PreconditionResult> CheckPermissionsAsync(ICommandContext context,CommandInfo command,IServiceProvider services)
{
if (context.User is SocketGuildUser sgu)
{
if (sgu.Roles.Select(x => x.Name == m_name).Contains(m_name)
{
return PreconditionResult.FromSuccess();
}
}
return PreconditionResult.FromError($"The user doesn't have the role '{m_name}'");
}
}
以及用途:
[Command("clear")]
[RequiresRole("RoleName")]
public async Task Clear(int amount)
{
IEnumerable<IMessage> messages = await Context.Channel.GetMessagesAsync(amount + 1).FlattenAsync();
await ((ITextChannel)Context.Channel).DeleteMessagesAsync(messages);
const int delay = 3000;
IUserMessage m = await ReplyAsync($"I have deleted {amount} messages");
await Task.Delay(delay);
await m.DeleteAsync();
Console.Write(amount + " was cleared in a channel");
}
,
这是你要做的:
您使用 RequireRoles 属性。
有四种方式:全部、任意、仅指定、无
假设您想发出禁令命令,但只希望管理员和模组能够使用它。你会这样做:
public class Moderation : BaseCommandModule
{
[Command("ban")]
[RequireRoles(RoleCheckMode.Any,"admin","mod")]
public async Task BanCommand(CommandContext ctx,DiscordMember name,[RemainingText] string reason)
{
}
}
,
您在这里做什么基本上是使用先决条件来检查用户角色中的任何是否具有ManageRoles
权限,描述令人困惑。
据我所知,Discord.net不会记录此类错误,仅将默认错误消息放入命令的Result
中,然后通常将其作为响应发送到通道。显然,您的代码必须在某些地方记录了此类错误。