2023-01-18 17:39:24 +03:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Globalization;
|
2022-05-14 16:12:24 +03:00
|
|
|
|
using System.Reflection;
|
2022-08-30 18:15:01 +03:00
|
|
|
|
using System.Text;
|
2021-12-15 22:07:04 +03:00
|
|
|
|
using System.Text.RegularExpressions;
|
2023-01-18 17:39:24 +03:00
|
|
|
|
using Boyfriend.Data;
|
2021-12-10 14:25:29 +03:00
|
|
|
|
using Discord;
|
|
|
|
|
using Discord.Net;
|
2022-05-14 16:12:24 +03:00
|
|
|
|
using Discord.WebSocket;
|
|
|
|
|
using Humanizer;
|
|
|
|
|
using Humanizer.Localisation;
|
2021-12-07 21:27:27 +03:00
|
|
|
|
|
|
|
|
|
namespace Boyfriend;
|
2021-12-07 15:52:37 +03:00
|
|
|
|
|
2022-12-08 11:51:49 +03:00
|
|
|
|
public static partial class Utils {
|
2022-11-11 22:59:11 +03:00
|
|
|
|
public static readonly Dictionary<string, CultureInfo> CultureInfoCache = new() {
|
2022-06-06 18:39:47 +03:00
|
|
|
|
{ "ru", new CultureInfo("ru-RU") },
|
2022-10-22 15:43:57 +03:00
|
|
|
|
{ "en", new CultureInfo("en-US") },
|
|
|
|
|
{ "mctaylors-ru", new CultureInfo("tt-RU") }
|
2022-05-14 16:12:24 +03:00
|
|
|
|
};
|
2022-06-06 18:39:47 +03:00
|
|
|
|
|
2023-01-18 17:39:24 +03:00
|
|
|
|
private static readonly Dictionary<string, string> ReflectionMessageCache = new();
|
2022-05-14 16:12:24 +03:00
|
|
|
|
|
|
|
|
|
private static readonly AllowedMentions AllowRoles = new() {
|
|
|
|
|
AllowedTypes = AllowedMentionTypes.Roles
|
|
|
|
|
};
|
2022-02-02 16:14:26 +03:00
|
|
|
|
|
2022-05-14 16:12:24 +03:00
|
|
|
|
public static string GetBeep(int i = -1) {
|
2022-11-11 22:59:11 +03:00
|
|
|
|
return GetMessage($"Beep{(i < 0 ? Random.Shared.Next(3) + 1 : ++i)}");
|
2022-01-18 20:38:15 +03:00
|
|
|
|
}
|
2021-12-15 22:07:04 +03:00
|
|
|
|
|
2022-06-06 18:39:47 +03:00
|
|
|
|
public static string? Wrap(string? original, bool limitedSpace = false) {
|
2022-11-11 22:59:11 +03:00
|
|
|
|
if (original is null) return null;
|
2022-06-06 18:39:47 +03:00
|
|
|
|
var maxChars = limitedSpace ? 970 : 1940;
|
|
|
|
|
if (original.Length > maxChars) original = original[..maxChars];
|
|
|
|
|
var style = original.Contains('\n') ? "```" : "`";
|
|
|
|
|
return $"{style}{original}{(original.Equals("") ? " " : "")}{style}";
|
2021-12-10 14:25:29 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-14 16:12:24 +03:00
|
|
|
|
public static string MentionChannel(ulong id) {
|
|
|
|
|
return $"<#{id}>";
|
2021-12-10 14:25:29 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-14 16:12:24 +03:00
|
|
|
|
public static ulong ParseMention(string mention) {
|
2022-12-08 11:51:49 +03:00
|
|
|
|
return ulong.TryParse(NumbersOnlyRegex().Replace(mention, ""), out var id) ? id : 0;
|
2021-12-15 22:07:04 +03:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-14 16:12:24 +03:00
|
|
|
|
public static async Task SendDirectMessage(SocketUser user, string toSend) {
|
2022-06-06 18:39:47 +03:00
|
|
|
|
try { await user.SendMessageAsync(toSend); } catch (HttpException e) {
|
2022-11-11 22:59:11 +03:00
|
|
|
|
if (e.DiscordCode is not DiscordErrorCode.CannotSendMessageToUser) throw;
|
2021-12-10 14:25:29 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-14 16:12:24 +03:00
|
|
|
|
public static async Task SilentSendAsync(SocketTextChannel? channel, string text, bool allowRoles = false) {
|
2022-11-16 21:27:10 +03:00
|
|
|
|
try {
|
|
|
|
|
if (channel is null || text.Length is 0 or > 2000)
|
2023-01-18 17:39:24 +03:00
|
|
|
|
throw new UnreachableException($"Message length is out of range: {text.Length}");
|
2022-11-16 21:27:10 +03:00
|
|
|
|
|
|
|
|
|
await channel.SendMessageAsync(text, false, null, null, allowRoles ? AllowRoles : AllowedMentions.None);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
await Boyfriend.Log(new LogMessage(LogSeverity.Error, nameof(Utils),
|
|
|
|
|
"Exception while silently sending message", e));
|
|
|
|
|
}
|
2021-12-15 22:07:04 +03:00
|
|
|
|
}
|
2022-06-06 18:39:47 +03:00
|
|
|
|
|
2022-02-02 16:14:26 +03:00
|
|
|
|
public static RequestOptions GetRequestOptions(string reason) {
|
|
|
|
|
var options = RequestOptions.Default;
|
|
|
|
|
options.AuditLogReason = reason;
|
|
|
|
|
return options;
|
|
|
|
|
}
|
2022-05-14 16:12:24 +03:00
|
|
|
|
|
|
|
|
|
public static string GetMessage(string name) {
|
|
|
|
|
var propertyName = name;
|
|
|
|
|
name = $"{Messages.Culture}/{name}";
|
2022-10-21 09:09:56 +03:00
|
|
|
|
if (ReflectionMessageCache.TryGetValue(name, out var cachedMessage)) return cachedMessage;
|
2022-05-14 16:12:24 +03:00
|
|
|
|
|
|
|
|
|
var toReturn =
|
|
|
|
|
typeof(Messages).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null)
|
2022-08-30 18:15:01 +03:00
|
|
|
|
?.ToString();
|
2022-11-11 22:59:11 +03:00
|
|
|
|
if (toReturn is null) {
|
|
|
|
|
Console.Error.WriteLine($@"Could not find localized property: {propertyName}");
|
2022-08-30 18:15:01 +03:00
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-14 16:12:24 +03:00
|
|
|
|
ReflectionMessageCache.Add(name, toReturn);
|
|
|
|
|
return toReturn;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-18 17:41:29 +03:00
|
|
|
|
public static async Task
|
2023-01-18 17:39:24 +03:00
|
|
|
|
SendFeedbackAsync(string feedback, SocketGuild guild, string mention, bool sendPublic = false) {
|
|
|
|
|
var data = GuildData.Get(guild);
|
|
|
|
|
var adminChannel = data.PrivateFeedbackChannel;
|
|
|
|
|
var systemChannel = data.PublicFeedbackChannel;
|
2022-11-11 22:59:11 +03:00
|
|
|
|
var toSend = $"*[{mention}: {feedback}]*";
|
|
|
|
|
if (adminChannel is not null) await SilentSendAsync(adminChannel, toSend);
|
|
|
|
|
if (sendPublic && systemChannel is not null) await SilentSendAsync(systemChannel, toSend);
|
2022-05-14 16:12:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-18 17:39:24 +03:00
|
|
|
|
public static string GetHumanizedTimeSpan(TimeSpan span) {
|
|
|
|
|
return span.TotalSeconds < 1
|
|
|
|
|
? Messages.Ever
|
|
|
|
|
: $" {span.Humanize(2, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Month, culture: Messages.Culture.Name.Contains("RU") ? CultureInfoCache["ru"] : Messages.Culture)}";
|
2022-05-14 16:12:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-18 17:39:24 +03:00
|
|
|
|
public static void SetCurrentLanguage(SocketGuild guild) {
|
|
|
|
|
Messages.Culture = CultureInfoCache[GuildData.Get(guild).Preferences["Lang"]];
|
2022-05-14 16:12:24 +03:00
|
|
|
|
}
|
2022-08-30 18:15:01 +03:00
|
|
|
|
|
|
|
|
|
public static void SafeAppendToBuilder(StringBuilder appendTo, string appendWhat, SocketTextChannel? channel) {
|
2022-11-11 22:59:11 +03:00
|
|
|
|
if (channel is null) return;
|
2022-08-30 18:15:01 +03:00
|
|
|
|
if (appendTo.Length + appendWhat.Length > 2000) {
|
|
|
|
|
_ = SilentSendAsync(channel, appendTo.ToString());
|
|
|
|
|
appendTo.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
appendTo.AppendLine(appendWhat);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SafeAppendToBuilder(StringBuilder appendTo, string appendWhat, SocketUserMessage message) {
|
|
|
|
|
if (appendTo.Length + appendWhat.Length > 2000) {
|
|
|
|
|
_ = message.ReplyAsync(appendTo.ToString(), false, null, AllowedMentions.None);
|
|
|
|
|
appendTo.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
appendTo.AppendLine(appendWhat);
|
|
|
|
|
}
|
2022-09-18 17:41:29 +03:00
|
|
|
|
|
2023-01-18 17:39:24 +03:00
|
|
|
|
public static SocketTextChannel? GetEventNotificationChannel(SocketGuild guild) {
|
|
|
|
|
return guild.GetTextChannel(ParseMention(GuildData.Get(guild)
|
|
|
|
|
.Preferences["EventNotificationChannel"]));
|
2022-09-18 17:41:29 +03:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-18 17:39:24 +03:00
|
|
|
|
public static bool UserExists(ulong id) {
|
|
|
|
|
return Boyfriend.Client.GetUser(id) is not null || UserInMemberData(id);
|
2022-09-18 17:41:29 +03:00
|
|
|
|
}
|
2022-10-18 20:55:16 +03:00
|
|
|
|
|
2023-01-18 17:39:24 +03:00
|
|
|
|
private static bool UserInMemberData(ulong id) {
|
|
|
|
|
return GuildData.GuildDataDictionary.Values.Any(gData => gData.MemberData.Values.Any(mData => mData.Id == id));
|
2022-10-23 12:49:49 +03:00
|
|
|
|
}
|
2022-11-11 22:59:11 +03:00
|
|
|
|
|
2023-01-18 17:39:24 +03:00
|
|
|
|
public static async Task<bool> UnmuteMemberAsync(GuildData data, string modDiscrim, SocketGuildUser toUnmute,
|
|
|
|
|
string reason) {
|
|
|
|
|
var requestOptions = GetRequestOptions($"({modDiscrim}) {reason}");
|
|
|
|
|
var role = data.MuteRole;
|
|
|
|
|
|
|
|
|
|
if (role is not null) {
|
|
|
|
|
if (!toUnmute.Roles.Contains(role)) return false;
|
|
|
|
|
if (data.Preferences["RemoveRolesOnMute"] is "true")
|
|
|
|
|
await toUnmute.AddRolesAsync(data.MemberData[toUnmute.Id].Roles, requestOptions);
|
|
|
|
|
await toUnmute.RemoveRoleAsync(role, requestOptions);
|
|
|
|
|
data.MemberData[toUnmute.Id].MutedUntil = null;
|
|
|
|
|
} else {
|
|
|
|
|
if (toUnmute.TimedOutUntil is null || toUnmute.TimedOutUntil.Value < DateTimeOffset.Now) return false;
|
|
|
|
|
|
|
|
|
|
await toUnmute.RemoveTimeOutAsync(requestOptions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2022-11-11 22:59:11 +03:00
|
|
|
|
}
|
2022-12-08 11:51:49 +03:00
|
|
|
|
|
|
|
|
|
[GeneratedRegex("[^0-9]")]
|
|
|
|
|
private static partial Regex NumbersOnlyRegex();
|
2022-09-18 17:41:29 +03:00
|
|
|
|
}
|