Как я мог проверить, есть ли у пользователя роль в discord.NET ?

#c# #discord.net

#c# #discord.net

Вопрос:

Я пытаюсь найти способ проверить, есть ли у пользователя роль X, и выполнить что-то, если у него ее нет, аналогично тому, как он регистрирует это на консоли, если вы используете [RequireUserPermission(GuildPermission.Administrator)] , просто я не хочу, чтобы он регистрировался на консоли, НАПРИМЕР:

 if (has role)
{
    // do stuff
} else
{
    // do stuff
}
  

Команда, в которую я пытаюсь это реализовать

 [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");
}
  

Комментарии:

1. Проверка того, есть ли у пользователя роль, и есть ли у пользователя данное разрешение, — это две разные вещи. Вам следует уточнить, что вы пытаетесь сделать. Кроме того, библиотека по умолчанию не регистрирует результаты предварительных условий в консоли. Вы будете тем, кто будет регистрировать это, поэтому, если вы не хотите входить в консоль, просто просмотрите свой код на предмет того, где вы в данный момент это делаете.

Ответ №1:

Как указал 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.");
        }
    }
}
  

Комментарии:

1. Проще использовать .Any вместо .Where и .FirstOrDefault с проверкой null

Ответ №2:

Я столкнулся с этой проблемой пару дней назад, моим решением было создать пользовательский атрибут, унаследованный от Discord.Commands.PreconditionAttribute

Я обнаружил это, когда использовал dotPeek в своей установке Visual Studio для декомпиляции и чтения того, как на самом деле работает служба команд, поскольку я хотел знать, как также работают их атрибуты. Как часть выполнения команды службой команд, она проверяет все предварительные условия для каждой команды, и только когда каждая из них удовлетворена, она выполняет функцию.

У этого класса есть функция, вызываемая 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");
}
  

Ответ №3:

Вот что вы делаете:

Вы используете атрибут RequireRoles .

У этого есть 4 различных способа: все, любой, только указанный, нет

Допустим, вы хотите создать команду запрета, но хотите, чтобы ее могли использовать только администратор и моды. Вы бы сделали это:

     public class Moderation : BaseCommandModule
{
    [Command("ban")]
    [RequireRoles(RoleCheckMode.Any, "admin", "mod")]
    public async Task BanCommand(CommandContext ctx, DiscordMember name, [RemainingText] string reason)
    {
        
    }
}
  

Ответ №4:

То, что вы здесь делаете, в основном использует предварительное условие для проверки, есть ли у какой-либо ManageRoles роли пользователя разрешение, описание сбивает с толку.

Насколько я знаю, Discord.net не регистрирует такие ошибки, только помещает сообщение об ошибке по умолчанию в Result команды, которое затем обычно отправляется на канал в качестве ответа. Очевидно, что должно быть какое-то место, где ваш код регистрирует такие ошибки.