using Discord; using System.Diagnostics.CodeAnalysis; using System.Text; using System.Text.RegularExpressions; namespace RegexBot.Common; /// /// Miscellaneous utility methods useful for the bot and modules. /// public static class Utilities { /// /// Gets a compiled regex that matches a channel tag and pulls its snowflake value. /// public static Regex ChannelMention { get; } = new(@"<#(?\d+)>", RegexOptions.Compiled); /// /// Gets a compiled regex that matches a custom emoji and pulls its name and ID. /// public static Regex CustomEmoji { get; } = new(@"<:(?[A-Za-z0-9_]{2,}):(?\d+)>", RegexOptions.Compiled); /// /// Gets a compiled regex that matches a fully formed Discord handle, extracting the name and discriminator. /// public static Regex DiscriminatorSearch { get; } = new(@"(.+)#(\d{4}(?!\d))", RegexOptions.Compiled); /// /// Gets a compiled regex that matches a user tag and pulls its snowflake value. /// public static Regex UserMention { get; } = new(@"<@!?(?\d+)>", RegexOptions.Compiled); /// /// Performs common checks on the specified message to see if it fits all the criteria of a /// typical, ordinary message sent by an ordinary guild user. /// public static bool IsValidUserMessage(SocketMessage msg, [NotNullWhen(true)] out SocketTextChannel? channel) { channel = default; if (msg.Channel is not SocketTextChannel ch) return false; if (msg.Author.IsBot || msg.Author.IsWebhook) return false; if (((IMessage)msg).Type != MessageType.Default) return false; if (msg is SocketSystemMessage) return false; channel = ch; return true; } /// /// Given a JToken, gets all string-based values out of it if the token may be a string /// or an array of strings. /// /// The JSON token to analyze and retrieve strings from. /// Thrown if the given token is not a string or array containing all strings. /// Thrown if the given token is null. public static List LoadStringOrStringArray(JToken? token) { const string ExNotString = "This token contains a non-string element."; if (token == null) throw new ArgumentNullException(nameof(token), "The provided token is null."); var results = new List(); if (token.Type == JTokenType.String) { results.Add(token.Value()!); } else if (token.Type == JTokenType.Array) { foreach (var entry in token.Values()) { if (entry.Type != JTokenType.String) throw new ArgumentException(ExNotString, nameof(token)); results.Add(entry.Value()!); } } else { throw new ArgumentException(ExNotString, nameof(token)); } return results; } /// /// Builds and returns an embed which displays this log entry. /// public static Embed BuildEmbed(this Data.ModLogEntry entry, RegexbotClient bot) { var issuedDisplay = TryFromEntityNameString(entry.IssuedBy, bot); string targetDisplay; var targetq = bot.EcQueryUser(entry.UserId.ToString()); if (targetq != null) targetDisplay = $"<@{targetq.UserId}> - {targetq.Username}#{targetq.Discriminator} `{targetq.UserId}`"; else targetDisplay = $"User with ID `{entry.UserId}`"; var logEmbed = new EmbedBuilder() .WithTitle(Enum.GetName(typeof(ModLogType), entry.LogType) + " logged:") .WithTimestamp(entry.Timestamp) .WithFooter($"Log #{entry.LogId}", bot.DiscordClient.CurrentUser.GetAvatarUrl()); // Escaping '#' not necessary here if (entry.Message != null) { logEmbed.Description = entry.Message; } var contextStr = new StringBuilder(); contextStr.AppendLine($"User: {targetDisplay}"); contextStr.AppendLine($"Logged by: {issuedDisplay}"); logEmbed.AddField(new EmbedFieldBuilder() { Name = "Context", Value = contextStr.ToString() }); return logEmbed.Build(); } /// /// Returns a representation of this entity that can be parsed by the constructor. /// public static string AsEntityNameString(this IUser entity) => $"@{entity.Id}::{entity.Username}"; /// /// If given string is in an EntityName format, returns a displayable representation of it based on /// a cache query. Otherwise, returns the input string as-is. /// [return: NotNullIfNotNull("input")] public static string? TryFromEntityNameString(string? input, RegexbotClient bot) { string? result = null; try { var entityTry = new EntityName(input!, EntityType.User); var issueq = bot.EcQueryUser(entityTry.Id!.Value.ToString()); if (issueq != null) result = $"<@{issueq.UserId}> - {issueq.Username}#{issueq.Discriminator} `{issueq.UserId}`"; else result = $"Unknown user with ID `{entityTry.Id!.Value}`"; } catch (Exception) { } return result ?? input; } }