using CommandLine; using Nadeko.Common.Medusa; namespace NadekoBot.Common; public sealed class CommandsUtilityService : ICommandsUtilityService, INService { private readonly CommandHandler _ch; private readonly IBotStrings _strings; private readonly DiscordPermOverrideService _dpos; private readonly IMessageSenderService _sender; private readonly ILocalization _loc; private readonly IMedusaLoaderService _medusae; public CommandsUtilityService( CommandHandler ch, IBotStrings strings, DiscordPermOverrideService dpos, IMessageSenderService sender, ILocalization loc, IMedusaLoaderService medusae) { _ch = ch; _strings = strings; _dpos = dpos; _sender = sender; _loc = loc; _medusae = medusae; } public EmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild) { var prefix = _ch.GetPrefix(guild); var str = $"**`{prefix + com.Aliases.First()}`**"; var alias = com.Aliases.Skip(1).FirstOrDefault(); if (alias is not null) str += $" **/ `{prefix + alias}`**"; var culture = _loc.GetCultureInfo(guild); var em = _sender.CreateEmbed() .AddField(str, $"{com.RealSummary(_strings, _medusae, culture, prefix)}", true); _dpos.TryGetOverrides(guild?.Id ?? 0, com.Name, out var overrides); var reqs = GetCommandRequirements(com, (GuildPermission?)overrides); if (reqs.Any()) em.AddField(GetText(strs.requires, guild), string.Join("\n", reqs)); em .WithOkColor() .AddField(_strings.GetText(strs.usage), string.Join("\n", com.RealRemarksArr(_strings, _medusae, culture, prefix).Map(arg => Format.Code(arg)))) .WithFooter(GetText(strs.module(com.Module.GetTopLevelModule().Name), guild)); var opt = GetNadekoOptionType(com.Attributes); if (opt is not null) { var hs = GetCommandOptionHelp(opt); if (!string.IsNullOrWhiteSpace(hs)) em.AddField(GetText(strs.options, guild), hs); } return em; } public static string GetCommandOptionHelp(Type opt) { var strs = GetCommandOptionHelpList(opt); return string.Join("\n", strs); } public static List GetCommandOptionHelpList(Type opt) { var strs = opt.GetProperties() .Select(x => x.GetCustomAttributes(true).FirstOrDefault(a => a is OptionAttribute)) .Where(x => x is not null) .Cast() .Select(x => { var toReturn = $"`--{x.LongName}`"; if (!string.IsNullOrWhiteSpace(x.ShortName)) toReturn += $" (`-{x.ShortName}`)"; toReturn += $" {x.HelpText} "; return toReturn; }) .ToList(); return strs; } public static Type? GetNadekoOptionType(IEnumerable attributes) => attributes .Select(a => a.GetType()) .Where(a => a.IsGenericType && a.GetGenericTypeDefinition() == typeof(NadekoOptionsAttribute<>)) .Select(a => a.GenericTypeArguments[0]) .FirstOrDefault(); public static string[] GetCommandRequirements(CommandInfo cmd, GuildPerm? overrides = null) { var toReturn = new List(); if (cmd.Preconditions.Any(x => x is OwnerOnlyAttribute)) toReturn.Add("Bot Owner Only"); if (cmd.Preconditions.Any(x => x is NoPublicBotAttribute) || cmd.Module .Preconditions .Any(x => x is NoPublicBotAttribute) || cmd.Module.GetTopLevelModule() .Preconditions .Any(x => x is NoPublicBotAttribute)) toReturn.Add("No Public Bot"); if (cmd.Preconditions .Any(x => x is OnlyPublicBotAttribute) || cmd.Module .Preconditions .Any(x => x is OnlyPublicBotAttribute) || cmd.Module.GetTopLevelModule() .Preconditions .Any(x => x is OnlyPublicBotAttribute)) toReturn.Add("Only Public Bot"); var userPermString = cmd.Preconditions .Where(ca => ca is UserPermAttribute) .Cast() .Select(userPerm => { if (userPerm.ChannelPermission is { } cPerm) return GetPreconditionString(cPerm); if (userPerm.GuildPermission is { } gPerm) return GetPreconditionString(gPerm); return string.Empty; }) .Where(x => !string.IsNullOrWhiteSpace(x)) .Join('\n'); if (overrides is null) { if (!string.IsNullOrWhiteSpace(userPermString)) toReturn.Add(userPermString); } else { if (!string.IsNullOrWhiteSpace(userPermString)) toReturn.Add(Format.Strikethrough(userPermString)); toReturn.Add(GetPreconditionString(overrides.Value)); } return toReturn.ToArray(); } public static string GetPreconditionString(ChannelPerm perm) => (perm + " Channel Permission").Replace("Guild", "Server"); public static string GetPreconditionString(GuildPerm perm) => (perm + " Server Permission").Replace("Guild", "Server"); public string GetText(LocStr str, IGuild? guild) => _strings.GetText(str, guild?.Id); } public interface ICommandsUtilityService { EmbedBuilder GetCommandHelp(CommandInfo com, IGuild guild); }