diff --git a/HuTao.Bot/Modules/Moderation/ModerationModule.cs b/HuTao.Bot/Modules/Moderation/ModerationModule.cs index ce2db12..cb7a036 100644 --- a/HuTao.Bot/Modules/Moderation/ModerationModule.cs +++ b/HuTao.Bot/Modules/Moderation/ModerationModule.cs @@ -1,8 +1,10 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; +using Humanizer; using HuTao.Data; using HuTao.Data.Models.Authorization; using HuTao.Data.Models.Moderation; @@ -57,29 +59,65 @@ public async Task BanAsync( await _error.AssociateError(Context.Message, "Failed to ban user."); } - [Priority(-2)] + [Priority(-1)] + [HiddenFromHelp] [Command("ban")] + [RequireAuthorization(AuthorizationScope.Ban)] + public Task BanAsync( + [RequireHigherRole] IUser user, uint deleteDays = 0, + [Remainder] string? reason = null) + => BanAsync(user, deleteDays, null, null, reason); + + [Priority(-2)] [HiddenFromHelp] + [Command("ban")] [RequireAuthorization(AuthorizationScope.Ban)] public Task BanAsync([RequireHigherRole] IUser user, [Remainder] string? reason = null) => BanAsync(user, 0, null, null, reason); - [Priority(-1)] + [Priority(-3)] + [HiddenFromHelp] [Command("ban")] + public async Task BanAsync( + [RequireHigherRole] IEnumerable users, + uint deleteDays = 0, TimeSpan? length = null, + [CheckCategory(AuthorizationScope.Ban)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await BanAsync(user, deleteDays, length, category, reason); + } + } + + [Priority(-4)] [HiddenFromHelp] + [Command("ban")] [RequireAuthorization(AuthorizationScope.Ban)] - public Task BanAsync( - [RequireHigherRole] IUser user, uint deleteDays = 0, + public async Task BanAsync( + [RequireHigherRole] IEnumerable users, + uint deleteDays = 0, [Remainder] string? reason = null) - => BanAsync(user, deleteDays, null, null, reason); + { + foreach (var user in users) + { + await BanAsync(user, deleteDays, null, null, reason); + } + } - [Priority(-1)] - [Command("mute")] + [Priority(-5)] [HiddenFromHelp] - [RequireAuthorization(AuthorizationScope.Mute)] - public Task HardMuteAsync([RequireHigherRole] IGuildUser user, - TimeSpan? length = null, [Remainder] string? reason = null) - => MuteAsync(user, length, null, reason); + [Command("ban")] + [RequireAuthorization(AuthorizationScope.Ban)] + public async Task BanAsync( + [RequireHigherRole] IEnumerable users, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await BanAsync(user, 0, null, null, reason); + } + } [Command("hardmute")] [Summary("Hard Mute a user from the current guild.")] @@ -99,13 +137,60 @@ await _error.AssociateError(Context.Message, "Failed to mute user. " + } } - [Priority(-2)] + [Priority(-1)] + [HiddenFromHelp] [Command("hardmute")] + [RequireAuthorization(AuthorizationScope.HardMute)] + public Task HardMuteAsync([RequireHigherRole] IGuildUser user, + TimeSpan? length = null, [Remainder] string? reason = null) + => HardMuteAsync(user, length, null, reason); + + [Priority(-2)] [HiddenFromHelp] - [RequireAuthorization(AuthorizationScope.Mute)] + [Command("hardmute")] + [RequireAuthorization(AuthorizationScope.HardMute)] public Task HardMuteAsync([RequireHigherRole] IGuildUser user, [Remainder] string? reason = null) => HardMuteAsync(user, null, null, reason); + [Priority(-3)] + [HiddenFromHelp] + [Command("hardmute")] + public async Task HardMuteAsync([RequireHigherRole] IEnumerable users, TimeSpan? length = null, + [CheckCategory(AuthorizationScope.HardMute)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await HardMuteAsync(user, length, category, reason); + } + } + + [Priority(-4)] + [HiddenFromHelp] + [Command("hardmute")] + [RequireAuthorization(AuthorizationScope.HardMute)] + public async Task HardMuteAsync([RequireHigherRole] IEnumerable users, + TimeSpan? length = null, [Remainder] string? reason = null) + { + foreach (var user in users) + { + await HardMuteAsync(user, length, null, reason); + } + } + + [Priority(-5)] + [HiddenFromHelp] + [Command("hardmute")] + [RequireAuthorization(AuthorizationScope.HardMute)] + public async Task HardMuteAsync([RequireHigherRole] IEnumerable users, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await HardMuteAsync(user, null, null, reason); + } + } + [Command("kick")] [Summary("Kick a user from the current guild.")] public async Task KickAsync([RequireHigherRole] IGuildUser user, @@ -120,12 +205,37 @@ public async Task KickAsync([RequireHigherRole] IGuildUser user, } [Priority(-1)] - [Command("kick")] [HiddenFromHelp] + [Command("kick")] [RequireAuthorization(AuthorizationScope.Kick)] public Task KickAsync([RequireHigherRole] IGuildUser user, [Remainder] string? reason = null) => KickAsync(user, null, reason); + [Priority(-2)] + [HiddenFromHelp] + [Command("kick")] + public async Task KickAsync([RequireHigherRole] IEnumerable users, + [CheckCategory(AuthorizationScope.Kick)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await KickAsync(user, category, reason); + } + } + + [Priority(-3)] + [HiddenFromHelp] + [Command("kick")] + [RequireAuthorization(AuthorizationScope.Kick)] + public async Task KickAsync([RequireHigherRole] IEnumerable users, [Remainder] string? reason = null) + { + foreach (var user in users) + { + await KickAsync(user, null, reason); + } + } + [Command("mute")] [Summary("Mute a user from the current guild.")] public async Task MuteAsync([RequireHigherRole] IGuildUser user, @@ -144,20 +254,59 @@ await _error.AssociateError(Context.Message, "Failed to mute user. " + } } - [Priority(-2)] + [Priority(-1)] + [HiddenFromHelp] [Command("mute")] + [RequireAuthorization(AuthorizationScope.Mute)] + public Task MuteAsync([RequireHigherRole] IGuildUser user, + TimeSpan? length = null, [Remainder] string? reason = null) + => MuteAsync(user, length, null, reason); + + [Priority(-2)] [HiddenFromHelp] + [Command("mute")] [RequireAuthorization(AuthorizationScope.Mute)] public Task MuteAsync([RequireHigherRole] IGuildUser user, [Remainder] string? reason = null) => MuteAsync(user, null, null, reason); - [Priority(-1)] - [Command("hardmute")] + [Priority(-3)] + [HiddenFromHelp] + [Command("mute")] + public async Task MuteAsync([RequireHigherRole] IEnumerable users, TimeSpan? length = null, + [CheckCategory(AuthorizationScope.Mute)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await MuteAsync(user, length, category, reason); + } + } + + [Priority(-4)] [HiddenFromHelp] + [Command("mute")] [RequireAuthorization(AuthorizationScope.Mute)] - public Task MuteAsync([RequireHigherRole] IGuildUser user, + public async Task MuteAsync([RequireHigherRole] IEnumerable users, TimeSpan? length = null, [Remainder] string? reason = null) - => HardMuteAsync(user, length, null, reason); + { + foreach (var user in users) + { + await MuteAsync(user, length, null, reason); + } + } + + [Priority(-5)] + [HiddenFromHelp] + [Command("mute")] + [RequireAuthorization(AuthorizationScope.Mute)] + public async Task MuteAsync([RequireHigherRole] IEnumerable users, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await MuteAsync(user, null, null, reason); + } + } [Priority(1)] [Command("mutes")] @@ -178,12 +327,37 @@ public async Task NoteAsync([RequireHigherRole] IUser user, } [Priority(-1)] - [Command("note")] [HiddenFromHelp] - [RequireAuthorization(AuthorizationScope.Mute)] + [Command("note")] + [RequireAuthorization(AuthorizationScope.Note)] public Task NoteAsync([RequireHigherRole] IUser user, [Remainder] string? note = null) => NoteAsync(user, null, note); + [Priority(-2)] + [Command("note")] + [Summary("Add a note to several users. Comma separated.")] + public async Task NoteAsync([RequireHigherRole] IEnumerable users, + [CheckCategory(AuthorizationScope.Note)] ModerationCategory? category = null, + [Remainder] string? note = null) + { + foreach (var user in users) + { + await NoteAsync(user, category, note); + } + } + + [Priority(-3)] + [HiddenFromHelp] + [Command("note")] + [RequireAuthorization(AuthorizationScope.Note)] + public async Task NoteAsync([RequireHigherRole] IEnumerable users, [Remainder] string? note = null) + { + foreach (var user in users) + { + await NoteAsync(user, null, note); + } + } + [Command("notice")] [Summary("Add a notice to a user. This counts as a minor warning.")] public async Task NoticeAsync([RequireHigherRole] IGuildUser user, @@ -195,12 +369,37 @@ public async Task NoticeAsync([RequireHigherRole] IGuildUser user, } [Priority(-1)] - [Command("notice")] [HiddenFromHelp] + [Command("notice")] [RequireAuthorization(AuthorizationScope.Warning)] public Task NoticeAsync([RequireHigherRole] IGuildUser user, [Remainder] string? reason = null) => NoticeAsync(user, null, reason); + [Priority(-2)] + [HiddenFromHelp] + [Command("notice")] + public async Task NoticeAsync([RequireHigherRole] IEnumerable users, + [CheckCategory(AuthorizationScope.Warning)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await NoticeAsync(user, category, reason); + } + } + + [Priority(-3)] + [HiddenFromHelp] + [Command("notice")] + [RequireAuthorization(AuthorizationScope.Warning)] + public async Task NoticeAsync([RequireHigherRole] IEnumerable users, [Remainder] string? reason = null) + { + foreach (var user in users) + { + await NoticeAsync(user, null, reason); + } + } + [Command("say")] [Summary("Make the bot send a message to the specified channel")] [RequireAuthorization(AuthorizationScope.Send)] @@ -234,7 +433,7 @@ public Task SlowmodeAsync(TimeSpan? length = null, ITextChannel? channel = null) [Priority(-1)] [Command("template")] [Alias("t")] [Summary("Run a configured moderation template")] - public async Task TemplateAsync(string name, [RequireHigherRole] IUser user) + public async Task TemplateAsync(string name, [RequireHigherRole] params IUser[] users) { var guild = await _db.Guilds.TrackGuildAsync(Context.Guild); var template = guild.ModerationTemplates @@ -252,11 +451,16 @@ public async Task TemplateAsync(string name, [RequireHigherRole] IUser user) return; } - var details = await GetDetailsAsync(user, template.Reason, null); - var result = await _moderation.ReprimandAsync(template, details); + var failed = new List(); + foreach (var user in users.DistinctBy(u => u.Id)) + { + var details = await GetDetailsAsync(user, template.Reason, null); + var result = await _moderation.ReprimandAsync(template, details); - if (result is null) - await _error.AssociateError(Context.Message, "Failed to use the template."); + if (result is null) failed.Add(user); + } + + if (failed.Count > 0) await ReplyAsync($"Failed to run template on {failed.Count} {failed.Humanize()}."); } [Command("unban")] @@ -273,11 +477,36 @@ public async Task UnbanAsync(IUser user, } [Priority(-1)] - [Command("unban")] [HiddenFromHelp] + [Command("unban")] [RequireAuthorization(AuthorizationScope.Ban)] public Task UnbanAsync(IUser user, [Remainder] string? reason = null) => UnbanAsync(user, null, reason); + [Priority(-2)] + [HiddenFromHelp] + [Command("unban")] + public async Task UnbanAsync(IEnumerable users, + [CheckCategory(AuthorizationScope.Ban)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await UnbanAsync(user, category, reason); + } + } + + [Priority(-3)] + [HiddenFromHelp] + [Command("unban")] + [RequireAuthorization(AuthorizationScope.Ban)] + public async Task UnbanAsync(IEnumerable users, [Remainder] string? reason = null) + { + foreach (var user in users) + { + await UnbanAsync(user, null, reason); + } + } + [Command("unmute")] [Summary("Unmute a user from the current guild.")] public async Task UnmuteAsync(IGuildUser user, @@ -292,11 +521,36 @@ public async Task UnmuteAsync(IGuildUser user, } [Priority(-1)] - [Command("unmute")] [HiddenFromHelp] + [Command("unmute")] [RequireAuthorization(AuthorizationScope.Mute)] public Task UnmuteAsync(IGuildUser user, [Remainder] string? reason = null) => UnmuteAsync(user, null, reason); + [Priority(-2)] + [HiddenFromHelp] + [Command("unmute")] + public async Task UnmuteAsync(IEnumerable users, + [CheckCategory(AuthorizationScope.Mute)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await UnmuteAsync(user, category, reason); + } + } + + [Priority(-3)] + [HiddenFromHelp] + [Command("unmute")] + [RequireAuthorization(AuthorizationScope.Mute)] + public async Task UnmuteAsync(IEnumerable users, [Remainder] string? reason = null) + { + foreach (var user in users) + { + await UnmuteAsync(user, null, reason); + } + } + [Command("warn")] [Summary("Warn a user from the current guild.")] public async Task WarnAsync([RequireHigherRole] IGuildUser user, @@ -308,27 +562,85 @@ public async Task WarnAsync([RequireHigherRole] IGuildUser user, } [Priority(-1)] - [Command("warn")] [HiddenFromHelp] + [Command("warn")] public Task WarnAsync([RequireHigherRole] IGuildUser user, uint amount = 1, [CheckCategory(AuthorizationScope.Warning)] ModerationCategory? category = null, [Remainder] string? reason = null) => WarnAsync(user, category, amount, reason); [Priority(-2)] + [HiddenFromHelp] [Command("warn")] + public Task WarnAsync([RequireHigherRole] IGuildUser user, + [CheckCategory(AuthorizationScope.Warning)] ModerationCategory? category = null, + [Remainder] string? reason = null) + => WarnAsync(user, category, 1, reason); + + [Priority(-3)] [HiddenFromHelp] + [Command("warn")] [RequireAuthorization(AuthorizationScope.Warning)] public Task WarnAsync([RequireHigherRole] IGuildUser user, uint amount = 1, [Remainder] string? reason = null) => WarnAsync(user, null, amount, reason); - [Priority(-3)] - [Command("warn")] + [Priority(-4)] [HiddenFromHelp] + [Command("warn")] [RequireAuthorization(AuthorizationScope.Warning)] public Task WarnAsync([RequireHigherRole] IGuildUser user, [Remainder] string? reason = null) => WarnAsync(user, null, 1, reason); + [Priority(-5)] + [HiddenFromHelp] + [Command("warn")] + public async Task WarnAsync(IEnumerable users, uint amount = 1, + [CheckCategory(AuthorizationScope.Warning)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await WarnAsync(user, category, amount, reason); + } + } + + [Priority(-6)] + [HiddenFromHelp] + [Command("warn")] + public async Task WarnAsync(IEnumerable users, + [CheckCategory(AuthorizationScope.Warning)] ModerationCategory? category = null, + [Remainder] string? reason = null) + { + foreach (var user in users) + { + await WarnAsync(user, category, 1, reason); + } + } + + [Priority(-7)] + [HiddenFromHelp] + [Command("warn")] + [RequireAuthorization(AuthorizationScope.Warning)] + public async Task WarnAsync(IEnumerable users, uint amount = 1, [Remainder] string? reason = null) + { + foreach (var user in users) + { + await WarnAsync(user, null, amount, reason); + } + } + + [Priority(-8)] + [HiddenFromHelp] + [Command("warn")] + [RequireAuthorization(AuthorizationScope.Warning)] + public async Task WarnAsync(IEnumerable users, [Remainder] string? reason = null) + { + foreach (var user in users) + { + await WarnAsync(user, null, 1, reason); + } + } + private async Task GetDetailsAsync( IUser user, string? reason, ModerationCategory? category) { diff --git a/HuTao.Services/Core/Preconditions/Commands/RequireHierarchyAttribute.cs b/HuTao.Services/Core/Preconditions/Commands/RequireHierarchyAttribute.cs index c0a02ea..36cd7d5 100644 --- a/HuTao.Services/Core/Preconditions/Commands/RequireHierarchyAttribute.cs +++ b/HuTao.Services/Core/Preconditions/Commands/RequireHierarchyAttribute.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Discord; using Discord.Commands; -using Discord.WebSocket; namespace HuTao.Services.Core.Preconditions.Commands; @@ -18,24 +17,21 @@ public override Task CheckPermissionsAsync( return value switch { - SocketRole[] roles => Task.FromResult(CheckHierarchy(roles, user)), - IRole[] roles => Task.FromResult(CheckHierarchy(roles, user)), - IEnumerable roles => Task.FromResult(CheckHierarchy(roles, user)), - IEnumerable roles => Task.FromResult(CheckHierarchy(roles, user)), + IEnumerable roles => Task.FromResult(CheckHierarchy(roles)), IRole role => role.Position >= user.Hierarchy ? Task.FromResult(PreconditionResult.FromError("This role is higher or equal than your roles.")) : Task.FromResult(PreconditionResult.FromSuccess()), _ => Task.FromResult(PreconditionResult.FromError("Role not found.")) }; - } - private static PreconditionResult CheckHierarchy(IEnumerable roles, IGuildUser user) - { - foreach (var role in roles.Where(role => role.Position >= user.Hierarchy)) + PreconditionResult CheckHierarchy(IEnumerable roles) { - return PreconditionResult.FromError($"{role} is higher or equal than your roles."); - } + foreach (var role in roles.Where(role => role.Position >= user.Hierarchy)) + { + return PreconditionResult.FromError($"{role} is higher or equal than your roles."); + } - return PreconditionResult.FromSuccess(); + return PreconditionResult.FromSuccess(); + } } } \ No newline at end of file diff --git a/HuTao.Services/Core/Preconditions/Commands/RequireHigherRoleAttribute.cs b/HuTao.Services/Core/Preconditions/Commands/RequireHigherRoleAttribute.cs index 9515e6d..ceae228 100644 --- a/HuTao.Services/Core/Preconditions/Commands/RequireHigherRoleAttribute.cs +++ b/HuTao.Services/Core/Preconditions/Commands/RequireHigherRoleAttribute.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Discord; using Discord.Commands; @@ -13,19 +14,32 @@ public override async Task CheckPermissionsAsync( if (context.User is not IGuildUser user) return PreconditionResult.FromError("This command cannot be used outside of a guild."); - if (value is not IGuildUser target) + var bot = await context.Guild.GetCurrentUserAsync().ConfigureAwait(false); + return value switch { - return value is IUser - ? PreconditionResult.FromSuccess() - : PreconditionResult.FromError("User not found."); - } + IEnumerable users => CheckUsers(users), + IGuildUser target => target.Hierarchy >= bot.Hierarchy + ? PreconditionResult.FromError($"The bot's role is lower than {target}.") + : target.Hierarchy >= user.Hierarchy + ? PreconditionResult.FromError($"You cannot {parameter.Command.Name} {target}.") + : PreconditionResult.FromSuccess(), + IEnumerable => PreconditionResult.FromSuccess(), + IUser => PreconditionResult.FromSuccess(), + _ => PreconditionResult.FromError("Invalid parameter type.") + }; + + PreconditionResult CheckUsers(IEnumerable users) + { + foreach (var u in users) + { + if (u.Hierarchy >= user.Hierarchy) + return PreconditionResult.FromError($"You cannot {parameter.Command.Name} {u}."); - if (user.Hierarchy <= target.Hierarchy) - return PreconditionResult.FromError($"You cannot {parameter.Command.Name} this user."); + if (u.Hierarchy >= bot.Hierarchy) + return PreconditionResult.FromError($"The bot's role is lower than {u}."); + } - var bot = await context.Guild.GetCurrentUserAsync().ConfigureAwait(false); - return bot?.Hierarchy <= target.Hierarchy - ? PreconditionResult.FromError("The bot's role is lower than the targeted user.") - : PreconditionResult.FromSuccess(); + return PreconditionResult.FromSuccess(); + } } } \ No newline at end of file diff --git a/HuTao.Services/Core/Preconditions/Interactions/RequireHierarchyAttribute.cs b/HuTao.Services/Core/Preconditions/Interactions/RequireHierarchyAttribute.cs index 99d2ded..e5ea595 100644 --- a/HuTao.Services/Core/Preconditions/Interactions/RequireHierarchyAttribute.cs +++ b/HuTao.Services/Core/Preconditions/Interactions/RequireHierarchyAttribute.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Discord; using Discord.Interactions; -using Discord.WebSocket; namespace HuTao.Services.Core.Preconditions.Interactions; @@ -18,24 +17,21 @@ public override Task CheckRequirementsAsync( return value switch { - SocketRole[] roles => Task.FromResult(CheckHierarchy(roles, user)), - IRole[] roles => Task.FromResult(CheckHierarchy(roles, user)), - IEnumerable roles => Task.FromResult(CheckHierarchy(roles, user)), - IEnumerable roles => Task.FromResult(CheckHierarchy(roles, user)), + IEnumerable roles => Task.FromResult(CheckHierarchy(roles)), IRole role => role.Position >= user.Hierarchy ? Task.FromResult(PreconditionResult.FromError("This role is higher or equal than your roles.")) : Task.FromResult(PreconditionResult.FromSuccess()), _ => Task.FromResult(PreconditionResult.FromError("Role not found.")) }; - } - private static PreconditionResult CheckHierarchy(IEnumerable roles, IGuildUser user) - { - foreach (var role in roles.Where(role => role.Position >= user.Hierarchy)) + PreconditionResult CheckHierarchy(IEnumerable roles) { - return PreconditionResult.FromError($"{role} is higher or equal than your roles."); - } + foreach (var role in roles.Where(role => role.Position >= user.Hierarchy)) + { + return PreconditionResult.FromError($"{role} is higher or equal than your roles."); + } - return PreconditionResult.FromSuccess(); + return PreconditionResult.FromSuccess(); + } } } \ No newline at end of file diff --git a/HuTao.Services/Core/Preconditions/Interactions/RequireHigherRoleAttribute.cs b/HuTao.Services/Core/Preconditions/Interactions/RequireHigherRoleAttribute.cs index 8d244e5..a431d6b 100644 --- a/HuTao.Services/Core/Preconditions/Interactions/RequireHigherRoleAttribute.cs +++ b/HuTao.Services/Core/Preconditions/Interactions/RequireHigherRoleAttribute.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; using Discord; using Discord.Interactions; @@ -13,19 +14,32 @@ public override async Task CheckRequirementsAsync( if (context.User is not IGuildUser user) return PreconditionResult.FromError("This command cannot be used outside of a guild."); - if (value is not IGuildUser target) + var bot = await context.Guild.GetCurrentUserAsync().ConfigureAwait(false); + return value switch { - return value is IUser - ? PreconditionResult.FromSuccess() - : PreconditionResult.FromError("User not found."); - } + IEnumerable users => CheckUsers(users), + IGuildUser target => target.Hierarchy >= bot.Hierarchy + ? PreconditionResult.FromError($"The bot's role is lower than {target}.") + : target.Hierarchy >= user.Hierarchy + ? PreconditionResult.FromError($"You cannot {parameter.Command.Name} {target}.") + : PreconditionResult.FromSuccess(), + IEnumerable => PreconditionResult.FromSuccess(), + IUser => PreconditionResult.FromSuccess(), + _ => PreconditionResult.FromError("Invalid parameter type.") + }; + + PreconditionResult CheckUsers(IEnumerable users) + { + foreach (var u in users) + { + if (u.Hierarchy >= user.Hierarchy) + return PreconditionResult.FromError($"You cannot {parameter.Command.Name} {u}."); - if (user.Hierarchy <= target.Hierarchy) - return PreconditionResult.FromError($"You cannot {parameter.Command.Name} this user."); + if (u.Hierarchy >= bot.Hierarchy) + return PreconditionResult.FromError($"The bot's role is lower than {u}."); + } - var bot = await context.Guild.GetCurrentUserAsync().ConfigureAwait(false); - return bot?.Hierarchy <= target.Hierarchy - ? PreconditionResult.FromError("The bot's role is lower than the targeted user.") - : PreconditionResult.FromSuccess(); + return PreconditionResult.FromSuccess(); + } } } \ No newline at end of file diff --git a/HuTao.Services/Core/TypeReaders/Commands/EnumerableTypeReader.cs b/HuTao.Services/Core/TypeReaders/Commands/EnumerableTypeReader.cs index 4ed6e90..c79439e 100644 --- a/HuTao.Services/Core/TypeReaders/Commands/EnumerableTypeReader.cs +++ b/HuTao.Services/Core/TypeReaders/Commands/EnumerableTypeReader.cs @@ -7,15 +7,15 @@ namespace HuTao.Services.Core.TypeReaders.Commands; public class EnumerableTypeReader : TypeReader { - private readonly string _separator; + private readonly string[] _separators; private readonly StringSplitOptions _splitOptions; private readonly TypeReader _typeReader; - public EnumerableTypeReader(TypeReader typeReader, string separator = ",", + public EnumerableTypeReader(TypeReader typeReader, string[]? separators = null, StringSplitOptions splitOptions = StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) { _typeReader = typeReader; - _separator = separator; + _separators = separators ?? new[] { ",", " ", "\r\n", "\r", "\n" }; _splitOptions = splitOptions; } @@ -23,7 +23,7 @@ public override async Task ReadAsync(ICommandContext context, IServiceProvider services) { var results = await input - .Split(_separator, _splitOptions).ToAsyncEnumerable() + .Split(_separators, _splitOptions).ToAsyncEnumerable() .SelectAwait(async i => await _typeReader.ReadAsync(context, i, services)) .SelectMany(r => r.Values?.ToAsyncEnumerable() ?? AsyncEnumerable.Empty()) .Select(v => v.Value).OfType() diff --git a/HuTao.Services/Core/TypeReaders/Commands/TypeReaderExtensions.cs b/HuTao.Services/Core/TypeReaders/Commands/TypeReaderExtensions.cs index b148935..2fb762b 100644 --- a/HuTao.Services/Core/TypeReaders/Commands/TypeReaderExtensions.cs +++ b/HuTao.Services/Core/TypeReaders/Commands/TypeReaderExtensions.cs @@ -24,10 +24,16 @@ public static void AddEnumerableTypeReader( public static void AddGuildTypeReader(this CommandService commands, CacheMode cacheMode = CacheMode.AllowDownload) where TGuild : class, IGuild - => commands.AddTypeReaders(new GuildTypeReader(cacheMode)); + { + commands.AddTypeReader(new GuildTypeReader(cacheMode)); + commands.AddEnumerableTypeReader(new GuildTypeReader(cacheMode)); + } public static void AddInviteTypeReader(this CommandService commands) where TInvite : class, IInvite - => commands.AddTypeReaders(new InviteTypeReader()); + { + commands.AddTypeReader(new InviteTypeReader()); + commands.AddEnumerableTypeReader(new InviteTypeReader()); + } public static void AddTypeReaders(this CommandService commands, params TypeReader[] readers) => commands.AddTypeReader(new TypeReaderCollection(readers)); @@ -37,5 +43,8 @@ public static void AddTypeReaders(this CommandService commands, IEnumer public static void AddUserTypeReader(this CommandService commands, CacheMode cacheMode = CacheMode.AllowDownload) where TUser : class, IUser - => commands.AddTypeReader(new UserTypeReader(cacheMode)); + { + commands.AddTypeReader(new UserTypeReader(cacheMode)); + commands.AddEnumerableTypeReader(new UserTypeReader(cacheMode)); + } } \ No newline at end of file