General code refactor (and a few breaking config changes)

This commit is contained in:
Octol1ttle 2022-11-12 00:59:11 +05:00
parent 0e144db2e2
commit 552c575dd2
Signed by: Octol1ttle
GPG key ID: B77C34313AEE1FFF
15 changed files with 1164 additions and 879 deletions

View file

@ -8,11 +8,10 @@ namespace Boyfriend;
public static class Boyfriend { public static class Boyfriend {
public static readonly StringBuilder StringBuilder = new(); public static readonly StringBuilder StringBuilder = new();
private static readonly Dictionary<ulong, SocketGuild> GuildCache = new();
private static readonly DiscordSocketConfig Config = new() { private static readonly DiscordSocketConfig Config = new() {
MessageCacheSize = 250, MessageCacheSize = 250,
GatewayIntents = GatewayIntents.All, GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.MessageContent | GatewayIntents.GuildMembers,
AlwaysDownloadUsers = true, AlwaysDownloadUsers = true,
AlwaysResolveStickers = false, AlwaysResolveStickers = false,
AlwaysDownloadDefaultStickers = false, AlwaysDownloadDefaultStickers = false,
@ -37,23 +36,20 @@ public static class Boyfriend {
new(); new();
public static readonly Dictionary<string, string> DefaultConfig = new() { public static readonly Dictionary<string, string> DefaultConfig = new() {
{ "Lang", "en" },
{ "Prefix", "!" }, { "Prefix", "!" },
{ "RemoveRolesOnMute", "false" }, { "Lang", "en" },
{ "SendWelcomeMessages", "true" },
{ "ReceiveStartupMessages", "false" }, { "ReceiveStartupMessages", "false" },
{ "FrowningFace", "true" }, { "WelcomeMessage", "default" },
{ "WelcomeMessage", Messages.DefaultWelcomeMessage }, { "SendWelcomeMessages", "true" },
{ "EventStartedReceivers", "interested,role" }, { "BotLogChannel", "0" },
{ "StarterRole", "0" }, { "StarterRole", "0" },
{ "MuteRole", "0" }, { "MuteRole", "0" },
{ "EventNotifyReceiverRole", "0" }, { "RemoveRolesOnMute", "false" },
{ "AdminLogChannel", "0" }, { "FrowningFace", "true" },
{ "BotLogChannel", "0" },
{ "EventCreatedChannel", "0" }, { "EventStartedReceivers", "interested,role" },
{ "EventStartedChannel", "0" }, { "EventNotificationRole", "0" },
{ "EventCancelledChannel", "0" }, { "EventNotificationChannel", "0" },
{ "EventCompletedChannel", "0" },
{ "EventEarlyNotificationOffset", "0" } { "EventEarlyNotificationOffset", "0" }
}; };
@ -81,8 +77,29 @@ public static class Boyfriend {
} }
private static Task Log(LogMessage msg) { private static Task Log(LogMessage msg) {
switch (msg.Severity) {
case LogSeverity.Critical:
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.Error.WriteLine(msg.ToString());
break;
case LogSeverity.Error:
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine(msg.ToString());
break;
case LogSeverity.Warning:
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(msg.ToString()); Console.WriteLine(msg.ToString());
break;
case LogSeverity.Info:
Console.WriteLine(msg.ToString());
break;
case LogSeverity.Verbose:
case LogSeverity.Debug:
default: return Task.CompletedTask;
}
Console.ResetColor();
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -95,9 +112,6 @@ public static class Boyfriend {
} }
public static Dictionary<string, string> GetGuildConfig(ulong id) { public static Dictionary<string, string> GetGuildConfig(ulong id) {
if (!RemovedRolesDictionary.ContainsKey(id))
RemovedRolesDictionary.Add(id, new Dictionary<ulong, ReadOnlyCollection<ulong>>());
if (GuildConfigDictionary.TryGetValue(id, out var cfg)) return cfg; if (GuildConfigDictionary.TryGetValue(id, out var cfg)) return cfg;
var path = $"config_{id}.json"; var path = $"config_{id}.json";
@ -110,13 +124,12 @@ public static class Boyfriend {
if (config.Keys.Count < DefaultConfig.Keys.Count) { if (config.Keys.Count < DefaultConfig.Keys.Count) {
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
// Avoids a closure allocation with the config variable // Conversion will result in a lot of memory allocations
foreach (var key in DefaultConfig.Keys) foreach (var key in DefaultConfig.Keys)
if (!config.ContainsKey(key)) if (!config.ContainsKey(key))
config.Add(key, DefaultConfig[key]); config.Add(key, DefaultConfig[key]);
} else if (config.Keys.Count > DefaultConfig.Keys.Count) { } else if (config.Keys.Count > DefaultConfig.Keys.Count) {
foreach (var key in config.Keys.Where(key => !DefaultConfig.ContainsKey(key))) foreach (var key in config.Keys.Where(key => !DefaultConfig.ContainsKey(key))) config.Remove(key);
config.Remove(key);
} }
GuildConfigDictionary.Add(id, config); GuildConfigDictionary.Add(id, config);
@ -126,10 +139,9 @@ public static class Boyfriend {
public static Dictionary<ulong, ReadOnlyCollection<ulong>> GetRemovedRoles(ulong id) { public static Dictionary<ulong, ReadOnlyCollection<ulong>> GetRemovedRoles(ulong id) {
if (RemovedRolesDictionary.TryGetValue(id, out var dict)) return dict; if (RemovedRolesDictionary.TryGetValue(id, out var dict)) return dict;
var path = $"removedroles_{id}.json"; var path = $"removedroles_{id}.json";
if (!File.Exists(path)) File.Create(path); if (!File.Exists(path)) File.Create(path).Dispose();
var json = File.ReadAllText(path); var json = File.ReadAllText(path);
var removedRoles = JsonConvert.DeserializeObject<Dictionary<ulong, ReadOnlyCollection<ulong>>>(json) var removedRoles = JsonConvert.DeserializeObject<Dictionary<ulong, ReadOnlyCollection<ulong>>>(json)
@ -139,18 +151,4 @@ public static class Boyfriend {
return removedRoles; return removedRoles;
} }
public static SocketGuild FindGuild(ulong channel) {
if (GuildCache.TryGetValue(channel, out var gld)) return gld;
foreach (var guild in Client.Guilds) {
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var x in guild.Channels)
if (x.Id == channel) {
GuildCache.Add(channel, guild);
return guild;
}
}
throw new Exception("Could not find guild by channel!");
}
} }

View file

@ -27,7 +27,6 @@ public sealed class CommandProcessor {
private readonly List<Task> _tasks = new(); private readonly List<Task> _tasks = new();
public readonly SocketCommandContext Context; public readonly SocketCommandContext Context;
private bool _serverBlacklisted;
public bool ConfigWriteScheduled = false; public bool ConfigWriteScheduled = false;
@ -39,6 +38,7 @@ public sealed class CommandProcessor {
var guild = Context.Guild; var guild = Context.Guild;
var config = Boyfriend.GetGuildConfig(guild.Id); var config = Boyfriend.GetGuildConfig(guild.Id);
var muteRole = Utils.GetMuteRole(guild); var muteRole = Utils.GetMuteRole(guild);
Utils.SetCurrentLanguage(guild.Id);
if (GetMember().Roles.Contains(muteRole)) { if (GetMember().Roles.Contains(muteRole)) {
await Context.Message.ReplyAsync(Messages.UserCannotUnmuteThemselves); await Context.Message.ReplyAsync(Messages.UserCannotUnmuteThemselves);
@ -49,15 +49,11 @@ public sealed class CommandProcessor {
var cleanList = Context.Message.CleanContent.Split("\n"); var cleanList = Context.Message.CleanContent.Split("\n");
for (var i = 0; i < list.Length; i++) { for (var i = 0; i < list.Length; i++) {
RunCommandOnLine(list[i], cleanList[i], config["Prefix"]); RunCommandOnLine(list[i], cleanList[i], config["Prefix"]);
if (_serverBlacklisted) {
await Context.Message.ReplyAsync(Messages.ServerBlacklisted);
return;
}
if (_stackedReplyMessage.Length > 0) _ = Context.Channel.TriggerTypingAsync(); if (_stackedReplyMessage.Length > 0) _ = Context.Channel.TriggerTypingAsync();
var member = Boyfriend.Client.GetGuild(Context.Guild.Id) var member = Boyfriend.Client.GetGuild(Context.Guild.Id)
.GetUser(Context.User.Id); // Getting an up-to-date copy .GetUser(Context.User.Id); // Getting an up-to-date copy
if (member == null || member.Roles.Contains(muteRole) if (member is null || member.Roles.Contains(muteRole)
|| member.TimedOutUntil.GetValueOrDefault(DateTimeOffset.UnixEpoch).ToUnixTimeSeconds() > || member.TimedOutUntil.GetValueOrDefault(DateTimeOffset.UnixEpoch).ToUnixTimeSeconds() >
DateTimeOffset.Now.ToUnixTimeSeconds()) break; DateTimeOffset.Now.ToUnixTimeSeconds()) break;
} }
@ -89,25 +85,25 @@ public sealed class CommandProcessor {
} }
public void Audit(string action, bool isPublic = true) { public void Audit(string action, bool isPublic = true) {
var format = string.Format(Messages.FeedbackFormat, Context.User.Mention, action); var format = $"*[{Context.User.Mention}: {action}]*";
if (isPublic) Utils.SafeAppendToBuilder(_stackedPublicFeedback, format, Context.Guild.SystemChannel); if (isPublic) Utils.SafeAppendToBuilder(_stackedPublicFeedback, format, Context.Guild.SystemChannel);
Utils.SafeAppendToBuilder(_stackedPrivateFeedback, format, Utils.GetAdminLogChannel(Context.Guild.Id)); Utils.SafeAppendToBuilder(_stackedPrivateFeedback, format, Utils.GetBotLogChannel(Context.Guild.Id));
if (_tasks.Count == 0) SendFeedbacks(false); if (_tasks.Count is 0) SendFeedbacks(false);
} }
private void SendFeedbacks(bool reply = true) { private void SendFeedbacks(bool reply = true) {
if (reply && _stackedReplyMessage.Length > 0) if (reply && _stackedReplyMessage.Length > 0)
_ = Context.Message.ReplyAsync(_stackedReplyMessage.ToString(), false, null, AllowedMentions.None); _ = Context.Message.ReplyAsync(_stackedReplyMessage.ToString(), false, null, AllowedMentions.None);
var adminChannel = Utils.GetAdminLogChannel(Context.Guild.Id); var adminChannel = Utils.GetBotLogChannel(Context.Guild.Id);
var systemChannel = Context.Guild.SystemChannel; var systemChannel = Context.Guild.SystemChannel;
if (_stackedPrivateFeedback.Length > 0 && adminChannel != null && if (_stackedPrivateFeedback.Length > 0 && adminChannel is not null &&
adminChannel.Id != Context.Message.Channel.Id) { adminChannel.Id != Context.Message.Channel.Id) {
_ = Utils.SilentSendAsync(adminChannel, _stackedPrivateFeedback.ToString()); _ = Utils.SilentSendAsync(adminChannel, _stackedPrivateFeedback.ToString());
_stackedPrivateFeedback.Clear(); _stackedPrivateFeedback.Clear();
} }
if (_stackedPublicFeedback.Length > 0 && systemChannel != null && systemChannel.Id != adminChannel?.Id if (_stackedPublicFeedback.Length > 0 && systemChannel is not null && systemChannel.Id != adminChannel?.Id
&& systemChannel.Id != Context.Message.Channel.Id) { && systemChannel.Id != Context.Message.Channel.Id) {
_ = Utils.SilentSendAsync(systemChannel, _stackedPublicFeedback.ToString()); _ = Utils.SilentSendAsync(systemChannel, _stackedPublicFeedback.ToString());
_stackedPublicFeedback.Clear(); _stackedPublicFeedback.Clear();
@ -115,7 +111,7 @@ public sealed class CommandProcessor {
} }
public string? GetRemaining(string[] from, int startIndex, string? argument) { public string? GetRemaining(string[] from, int startIndex, string? argument) {
if (startIndex >= from.Length && argument != null) if (startIndex >= from.Length && argument is not null)
Utils.SafeAppendToBuilder(_stackedReplyMessage, Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{MissingArgument}{Utils.GetMessage($"Missing{argument}")}", Context.Message); $"{MissingArgument}{Utils.GetMessage($"Missing{argument}")}", Context.Message);
else return string.Join(" ", from, startIndex, from.Length - startIndex); else return string.Join(" ", from, startIndex, from.Length - startIndex);
@ -129,8 +125,8 @@ public sealed class CommandProcessor {
return null; return null;
} }
var user = Utils.ParseUser(args[index]); var user = Boyfriend.Client.GetUser(Utils.ParseMention(args[index]));
if (user == null && argument != null) if (user is null && argument is not null)
Utils.SafeAppendToBuilder(_stackedReplyMessage, Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Messages.InvalidUser, Utils.Wrap(cleanArgs[index]))}", $"{InvalidArgument}{string.Format(Messages.InvalidUser, Utils.Wrap(cleanArgs[index]))}",
Context.Message); Context.Message);
@ -154,7 +150,7 @@ public sealed class CommandProcessor {
public SocketGuildUser? GetMember(SocketUser user, string? argument) { public SocketGuildUser? GetMember(SocketUser user, string? argument) {
var member = Context.Guild.GetUser(user.Id); var member = Context.Guild.GetUser(user.Id);
if (member == null && argument != null) if (member is null && argument is not null)
Utils.SafeAppendToBuilder(_stackedReplyMessage, $":x: {Messages.UserNotInGuild}", Context.Message); Utils.SafeAppendToBuilder(_stackedReplyMessage, $":x: {Messages.UserNotInGuild}", Context.Message);
return member; return member;
} }
@ -167,7 +163,7 @@ public sealed class CommandProcessor {
} }
var member = Context.Guild.GetUser(Utils.ParseMention(args[index])); var member = Context.Guild.GetUser(Utils.ParseMention(args[index]));
if (member == null && argument != null) if (member is null && argument is not null)
Utils.SafeAppendToBuilder(_stackedReplyMessage, Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Messages.InvalidMember, Utils.Wrap(cleanArgs[index]))}", $"{InvalidArgument}{string.Format(Messages.InvalidMember, Utils.Wrap(cleanArgs[index]))}",
Context.Message); Context.Message);
@ -186,7 +182,7 @@ public sealed class CommandProcessor {
} }
var id = Utils.ParseMention(args[index]); var id = Utils.ParseMention(args[index]);
if (Context.Guild.GetBanAsync(id) == null) { if (Context.Guild.GetBanAsync(id) is null) {
Utils.SafeAppendToBuilder(_stackedReplyMessage, Messages.UserNotBanned, Context.Message); Utils.SafeAppendToBuilder(_stackedReplyMessage, Messages.UserNotBanned, Context.Message);
return null; return null;
} }
@ -209,7 +205,7 @@ public sealed class CommandProcessor {
return null; return null;
} }
if (argument == null) return i; if (argument is null) return i;
if (i < min) { if (i < min) {
Utils.SafeAppendToBuilder(_stackedReplyMessage, Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Utils.GetMessage($"{argument}TooSmall"), min.ToString())}", $"{InvalidArgument}{string.Format(Utils.GetMessage($"{argument}TooSmall"), min.ToString())}",
@ -232,7 +228,7 @@ public sealed class CommandProcessor {
int days = 0, hours = 0, minutes = 0, seconds = 0; int days = 0, hours = 0, minutes = 0, seconds = 0;
foreach (var c in chars) foreach (var c in chars)
if (char.IsDigit(c)) { numberBuilder.Append(c); } else { if (char.IsDigit(c)) { numberBuilder.Append(c); } else {
if (numberBuilder.Length == 0) return infinity; if (numberBuilder.Length is 0) return infinity;
switch (c) { switch (c) {
case 'd' or 'D' or 'д' or 'Д': case 'd' or 'D' or 'д' or 'Д':
days += int.Parse(numberBuilder.ToString()); days += int.Parse(numberBuilder.ToString());

View file

@ -8,19 +8,17 @@ public sealed class BanCommand : ICommand {
public async Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) { public async Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) {
var toBan = cmd.GetUser(args, cleanArgs, 0, "ToBan"); var toBan = cmd.GetUser(args, cleanArgs, 0, "ToBan");
if (toBan == null || !cmd.HasPermission(GuildPermission.BanMembers)) return; if (toBan is null || !cmd.HasPermission(GuildPermission.BanMembers)) return;
var memberToBan = cmd.GetMember(toBan, null); var memberToBan = cmd.GetMember(toBan, null);
if (memberToBan != null && !cmd.CanInteractWith(memberToBan, "Ban")) return; if (memberToBan is not null && !cmd.CanInteractWith(memberToBan, "Ban")) return;
var duration = CommandProcessor.GetTimeSpan(args, 1); var duration = CommandProcessor.GetTimeSpan(args, 1);
var reason = cmd.GetRemaining(args, duration.TotalSeconds < 1 ? 1 : 2, "BanReason"); var reason = cmd.GetRemaining(args, duration.TotalSeconds < 1 ? 1 : 2, "BanReason");
if (reason == null) return; if (reason is not null) await BanUserAsync(cmd, toBan, duration, reason);
await BanUser(cmd, toBan, duration, reason);
} }
public static async Task BanUser(CommandProcessor cmd, SocketUser toBan, TimeSpan duration, string reason) { private static async Task BanUserAsync(CommandProcessor cmd, SocketUser toBan, TimeSpan duration, string reason) {
var author = cmd.Context.User; var author = cmd.Context.User;
var guild = cmd.Context.Guild; var guild = cmd.Context.Guild;
await Utils.SendDirectMessage(toBan, await Utils.SendDirectMessage(toBan,

View file

@ -12,7 +12,7 @@ public sealed class ClearCommand : ICommand {
if (!cmd.HasPermission(GuildPermission.ManageMessages)) return; if (!cmd.HasPermission(GuildPermission.ManageMessages)) return;
var toDelete = cmd.GetNumberRange(cleanArgs, 0, 1, 200, "ClearAmount"); var toDelete = cmd.GetNumberRange(cleanArgs, 0, 1, 200, "ClearAmount");
if (toDelete == null) return; if (toDelete is null) return;
var messages = await channel.GetMessagesAsync((int)(toDelete + 1)).FlattenAsync(); var messages = await channel.GetMessagesAsync((int)(toDelete + 1)).FlattenAsync();
var user = (SocketGuildUser)cmd.Context.User; var user = (SocketGuildUser)cmd.Context.User;

View file

@ -8,15 +8,14 @@ public sealed class KickCommand : ICommand {
public async Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) { public async Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) {
var toKick = cmd.GetMember(args, cleanArgs, 0, "ToKick"); var toKick = cmd.GetMember(args, cleanArgs, 0, "ToKick");
if (toKick == null || !cmd.HasPermission(GuildPermission.KickMembers)) return; if (toKick is null || !cmd.HasPermission(GuildPermission.KickMembers)) return;
if (!cmd.CanInteractWith(toKick, "Kick")) return;
if (cmd.CanInteractWith(toKick, "Kick"))
await KickMemberAsync(cmd, toKick, cmd.GetRemaining(args, 1, "KickReason")); await KickMemberAsync(cmd, toKick, cmd.GetRemaining(args, 1, "KickReason"));
} }
private static async Task KickMemberAsync(CommandProcessor cmd, SocketGuildUser toKick, string? reason) { private static async Task KickMemberAsync(CommandProcessor cmd, SocketGuildUser toKick, string? reason) {
if (reason == null) return; if (reason is null) return;
var guildKickMessage = $"({cmd.Context.User}) {reason}"; var guildKickMessage = $"({cmd.Context.User}) {reason}";
await Utils.SendDirectMessage(toKick, await Utils.SendDirectMessage(toKick,

View file

@ -9,15 +9,15 @@ public sealed class MuteCommand : ICommand {
public async Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) { public async Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) {
var toMute = cmd.GetMember(args, cleanArgs, 0, "ToMute"); var toMute = cmd.GetMember(args, cleanArgs, 0, "ToMute");
if (toMute == null) return; if (toMute is null) return;
var duration = CommandProcessor.GetTimeSpan(args, 1); var duration = CommandProcessor.GetTimeSpan(args, 1);
var reason = cmd.GetRemaining(args, duration.TotalSeconds < 1 ? 1 : 2, "MuteReason"); var reason = cmd.GetRemaining(args, duration.TotalSeconds < 1 ? 1 : 2, "MuteReason");
if (reason == null) return; if (reason is null) return;
var role = Utils.GetMuteRole(cmd.Context.Guild); var role = Utils.GetMuteRole(cmd.Context.Guild);
if ((role != null && toMute.Roles.Contains(role)) if ((role is not null && toMute.Roles.Contains(role))
|| (toMute.TimedOutUntil != null || (toMute.TimedOutUntil is not null
&& toMute.TimedOutUntil.Value.ToUnixTimeSeconds() && toMute.TimedOutUntil.Value.ToUnixTimeSeconds()
> DateTimeOffset.Now.ToUnixTimeSeconds())) { > DateTimeOffset.Now.ToUnixTimeSeconds())) {
cmd.Reply(Messages.MemberAlreadyMuted, ":x: "); cmd.Reply(Messages.MemberAlreadyMuted, ":x: ");
@ -33,8 +33,7 @@ public sealed class MuteCommand : ICommand {
cmd.Reply(Messages.RolesReturned, ":warning: "); cmd.Reply(Messages.RolesReturned, ":warning: ");
} }
if (!cmd.HasPermission(GuildPermission.ModerateMembers) || !cmd.CanInteractWith(toMute, "Mute")) return; if (cmd.HasPermission(GuildPermission.ModerateMembers) && cmd.CanInteractWith(toMute, "Mute"))
await MuteMemberAsync(cmd, toMute, duration, reason); await MuteMemberAsync(cmd, toMute, duration, reason);
} }
@ -46,7 +45,7 @@ public sealed class MuteCommand : ICommand {
var role = Utils.GetMuteRole(guild); var role = Utils.GetMuteRole(guild);
var hasDuration = duration.TotalSeconds > 0; var hasDuration = duration.TotalSeconds > 0;
if (role != null) { if (role is not null) {
if (config["RemoveRolesOnMute"] is "true") { if (config["RemoveRolesOnMute"] is "true") {
var rolesRemoved = new List<ulong>(); var rolesRemoved = new List<ulong>();
foreach (var userRole in toMute.Roles) foreach (var userRole in toMute.Roles)

View file

@ -11,7 +11,7 @@ public sealed class SettingsCommand : ICommand {
var guild = cmd.Context.Guild; var guild = cmd.Context.Guild;
var config = Boyfriend.GetGuildConfig(guild.Id); var config = Boyfriend.GetGuildConfig(guild.Id);
if (args.Length == 0) { if (args.Length is 0) {
var currentSettings = Boyfriend.StringBuilder.AppendLine(Messages.CurrentSettings); var currentSettings = Boyfriend.StringBuilder.AppendLine(Messages.CurrentSettings);
foreach (var setting in Boyfriend.DefaultConfig) { foreach (var setting in Boyfriend.DefaultConfig) {
@ -19,20 +19,14 @@ public sealed class SettingsCommand : ICommand {
var currentValue = config[setting.Key]; var currentValue = config[setting.Key];
if (setting.Key.EndsWith("Channel")) { if (setting.Key.EndsWith("Channel")) {
if (guild.GetTextChannel(Convert.ToUInt64(currentValue)) != null) if (guild.GetTextChannel(ulong.Parse(currentValue)) is not null) format = "<#{0}>";
format = "<#{0}>"; else currentValue = Messages.ChannelNotSpecified;
else
currentValue = Messages.ChannelNotSpecified;
} else if (setting.Key.EndsWith("Role")) { } else if (setting.Key.EndsWith("Role")) {
if (guild.GetRole(Convert.ToUInt64(currentValue)) != null) if (guild.GetRole(ulong.Parse(currentValue)) is not null) format = "<@&{0}>";
format = "<@&{0}>"; else currentValue = Messages.RoleNotSpecified;
else
currentValue = Messages.RoleNotSpecified;
} else { } else {
if (IsBool(currentValue)) if (!IsBool(currentValue)) format = Utils.Wrap("{0}")!;
currentValue = YesOrNo(currentValue is "true"); else currentValue = YesOrNo(currentValue is "true");
else
format = Utils.Wrap("{0}")!;
} }
currentSettings.Append($"{Utils.GetMessage($"Settings{setting.Key}")} (`{setting.Key}`): ") currentSettings.Append($"{Utils.GetMessage($"Settings{setting.Key}")} (`{setting.Key}`): ")
@ -65,11 +59,11 @@ public sealed class SettingsCommand : ICommand {
if (args.Length >= 2) { if (args.Length >= 2) {
value = cmd.GetRemaining(args, 1, "Setting"); value = cmd.GetRemaining(args, 1, "Setting");
if (value == null) return Task.CompletedTask; if (value is null) return Task.CompletedTask;
if (selectedSetting is "EventStartedReceivers") { if (selectedSetting is "EventStartedReceivers") {
value = value.Replace(" ", "").ToLower(); value = value.Replace(" ", "").ToLower();
if (value.StartsWith(",") || value.Count(x => x == ',') > 1 || if (value.StartsWith(",") || value.Count(x => x is ',') > 1 ||
(!value.Contains("interested") && !value.Contains("role"))) { (!value.Contains("interested") && !value.Contains("users") && !value.Contains("role"))) {
cmd.Reply(Messages.InvalidSettingValue, ":x: "); cmd.Reply(Messages.InvalidSettingValue, ":x: ");
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -91,14 +85,12 @@ public sealed class SettingsCommand : ICommand {
var localizedSelectedSetting = Utils.GetMessage($"Settings{selectedSetting}"); var localizedSelectedSetting = Utils.GetMessage($"Settings{selectedSetting}");
var mention = Utils.ParseMention(value); var mention = Utils.ParseMention(value);
if (mention != 0 && selectedSetting is not "WelcomeMessage") value = mention.ToString(); if (mention is not 0 && selectedSetting is not "WelcomeMessage") value = mention.ToString();
var formatting = Utils.Wrap("{0}")!; var formatting = Utils.Wrap("{0}")!;
if (selectedSetting is not "WelcomeMessage") { if (selectedSetting is not "WelcomeMessage") {
if (selectedSetting.EndsWith("Channel")) if (selectedSetting.EndsWith("Channel")) formatting = "<#{0}>";
formatting = "<#{0}>"; if (selectedSetting.EndsWith("Role")) formatting = "<@&{0}>";
if (selectedSetting.EndsWith("Role"))
formatting = "<@&{0}>";
} }
var formattedValue = selectedSetting switch { var formattedValue = selectedSetting switch {
@ -110,9 +102,7 @@ public sealed class SettingsCommand : ICommand {
}; };
if (value is "reset" or "default") { if (value is "reset" or "default") {
config[selectedSetting] = selectedSetting is "WelcomeMessage" config[selectedSetting] = Boyfriend.DefaultConfig[selectedSetting];
? Messages.DefaultWelcomeMessage
: Boyfriend.DefaultConfig[selectedSetting];
} else { } else {
if (value == config[selectedSetting]) { if (value == config[selectedSetting]) {
cmd.Reply(string.Format(Messages.SettingsNothingChanged, localizedSelectedSetting, formattedValue), cmd.Reply(string.Format(Messages.SettingsNothingChanged, localizedSelectedSetting, formattedValue),
@ -120,17 +110,17 @@ public sealed class SettingsCommand : ICommand {
return Task.CompletedTask; return Task.CompletedTask;
} }
if (selectedSetting is "Lang" && value is not "ru" and not "en" and not "mctaylors-ru") { if (selectedSetting is "Lang" && !Utils.CultureInfoCache.ContainsKey(value)) {
cmd.Reply(Messages.LanguageNotSupported, ":x: "); cmd.Reply(Messages.LanguageNotSupported, ":x: ");
return Task.CompletedTask; return Task.CompletedTask;
} }
if (selectedSetting.EndsWith("Channel") && guild.GetTextChannel(mention) == null) { if (selectedSetting.EndsWith("Channel") && guild.GetTextChannel(mention) is null) {
cmd.Reply(Messages.InvalidChannel, ":x: "); cmd.Reply(Messages.InvalidChannel, ":x: ");
return Task.CompletedTask; return Task.CompletedTask;
} }
if (selectedSetting.EndsWith("Role") && guild.GetRole(mention) == null) { if (selectedSetting.EndsWith("Role") && guild.GetRole(mention) is null) {
cmd.Reply(Messages.InvalidRole, ":x: "); cmd.Reply(Messages.InvalidRole, ":x: ");
return Task.CompletedTask; return Task.CompletedTask;
} }

View file

@ -9,11 +9,9 @@ public sealed class UnbanCommand : ICommand {
if (!cmd.HasPermission(GuildPermission.BanMembers)) return; if (!cmd.HasPermission(GuildPermission.BanMembers)) return;
var id = cmd.GetBan(args, 0); var id = cmd.GetBan(args, 0);
if (id == null) return; if (id is null) return;
var reason = cmd.GetRemaining(args, 1, "UnbanReason"); var reason = cmd.GetRemaining(args, 1, "UnbanReason");
if (reason == null) return; if (reason is not null) await UnbanUserAsync(cmd, id.Value, reason);
await UnbanUserAsync(cmd, id.Value, reason);
} }
public static async Task UnbanUserAsync(CommandProcessor cmd, ulong id, string reason) { public static async Task UnbanUserAsync(CommandProcessor cmd, ulong id, string reason) {

View file

@ -10,8 +10,9 @@ public sealed class UnmuteCommand : ICommand {
if (!cmd.HasPermission(GuildPermission.ModerateMembers)) return; if (!cmd.HasPermission(GuildPermission.ModerateMembers)) return;
var toUnmute = cmd.GetMember(args, cleanArgs, 0, "ToUnmute"); var toUnmute = cmd.GetMember(args, cleanArgs, 0, "ToUnmute");
if (toUnmute is null) return;
var reason = cmd.GetRemaining(args, 1, "UnmuteReason"); var reason = cmd.GetRemaining(args, 1, "UnmuteReason");
if (toUnmute == null || reason == null || !cmd.CanInteractWith(toUnmute, "Unmute")) return; if (reason is not null && cmd.CanInteractWith(toUnmute, "Unmute"))
await UnmuteMemberAsync(cmd, toUnmute, reason); await UnmuteMemberAsync(cmd, toUnmute, reason);
} }
@ -20,7 +21,7 @@ public sealed class UnmuteCommand : ICommand {
var requestOptions = Utils.GetRequestOptions($"({cmd.Context.User}) {reason}"); var requestOptions = Utils.GetRequestOptions($"({cmd.Context.User}) {reason}");
var role = Utils.GetMuteRole(cmd.Context.Guild); var role = Utils.GetMuteRole(cmd.Context.Guild);
if (role != null && toUnmute.Roles.Contains(role)) { if (role is not null && toUnmute.Roles.Contains(role)) {
var rolesRemoved = Boyfriend.GetRemovedRoles(cmd.Context.Guild.Id); var rolesRemoved = Boyfriend.GetRemovedRoles(cmd.Context.Guild.Id);
if (rolesRemoved.TryGetValue(toUnmute.Id, out var unmutedRemovedRoles)) { if (rolesRemoved.TryGetValue(toUnmute.Id, out var unmutedRemovedRoles)) {
@ -31,7 +32,7 @@ public sealed class UnmuteCommand : ICommand {
await toUnmute.RemoveRoleAsync(role, requestOptions); await toUnmute.RemoveRoleAsync(role, requestOptions);
} else { } else {
if (toUnmute.TimedOutUntil == null || toUnmute.TimedOutUntil.Value.ToUnixTimeSeconds() < if (toUnmute.TimedOutUntil is null || toUnmute.TimedOutUntil.Value.ToUnixTimeSeconds() <
DateTimeOffset.Now.ToUnixTimeSeconds()) { DateTimeOffset.Now.ToUnixTimeSeconds()) {
cmd.Reply(Messages.MemberNotMuted, ":x: "); cmd.Reply(Messages.MemberNotMuted, ":x: ");
return; return;

View file

@ -1,7 +1,6 @@
using Discord; using Discord;
using Discord.Rest; using Discord.Rest;
using Discord.WebSocket; using Discord.WebSocket;
using Humanizer;
namespace Boyfriend; namespace Boyfriend;
@ -23,14 +22,14 @@ public static class EventHandler {
private static Task ReadyEvent() { private static Task ReadyEvent() {
if (!_sendReadyMessages) return Task.CompletedTask; if (!_sendReadyMessages) return Task.CompletedTask;
var i = Utils.Random.Next(3); var i = Random.Shared.Next(3);
foreach (var guild in Client.Guilds) { foreach (var guild in Client.Guilds) {
var config = Boyfriend.GetGuildConfig(guild.Id); var config = Boyfriend.GetGuildConfig(guild.Id);
var channel = guild.GetTextChannel(Convert.ToUInt64(config["BotLogChannel"])); var channel = guild.GetTextChannel(Utils.ParseMention(config["BotLogChannel"]));
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild.Id);
if (config["ReceiveStartupMessages"] is not "true" || channel == null) continue; if (config["ReceiveStartupMessages"] is not "true" || channel is null) continue;
_ = channel.SendMessageAsync(string.Format(Messages.Ready, Utils.GetBeep(i))); _ = channel.SendMessageAsync(string.Format(Messages.Ready, Utils.GetBeep(i)));
} }
@ -41,9 +40,10 @@ public static class EventHandler {
private static async Task MessageDeletedEvent(Cacheable<IMessage, ulong> message, private static async Task MessageDeletedEvent(Cacheable<IMessage, ulong> message,
Cacheable<IMessageChannel, ulong> channel) { Cacheable<IMessageChannel, ulong> channel) {
var msg = message.Value; var msg = message.Value;
if (msg is null or ISystemMessage || msg.Author.IsBot) return; if (channel.Value is not SocketGuildChannel gChannel || msg is null or ISystemMessage ||
msg.Author.IsBot) return;
var guild = Boyfriend.FindGuild(channel.Value.Id); var guild = gChannel.Guild;
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild.Id);
@ -61,11 +61,7 @@ public static class EventHandler {
} }
private static Task MessageReceivedEvent(SocketMessage messageParam) { private static Task MessageReceivedEvent(SocketMessage messageParam) {
if (messageParam is not SocketUserMessage { Author: SocketGuildUser user } message) return Task.CompletedTask; if (messageParam is not SocketUserMessage message) return Task.CompletedTask;
var guild = user.Guild;
Utils.SetCurrentLanguage(guild.Id);
_ = message.CleanContent.ToLower() switch { _ = message.CleanContent.ToLower() switch {
"whoami" => message.ReplyAsync("`nobody`"), "whoami" => message.ReplyAsync("`nobody`"),
@ -81,11 +77,10 @@ public static class EventHandler {
private static async Task MessageUpdatedEvent(Cacheable<IMessage, ulong> messageCached, SocketMessage messageSocket, private static async Task MessageUpdatedEvent(Cacheable<IMessage, ulong> messageCached, SocketMessage messageSocket,
ISocketMessageChannel channel) { ISocketMessageChannel channel) {
var msg = messageCached.Value; var msg = messageCached.Value;
if (channel is not SocketGuildChannel gChannel || msg is null or ISystemMessage ||
msg.CleanContent == messageSocket.CleanContent || msg.Author.IsBot) return;
if (msg is null or ISystemMessage || msg.CleanContent == messageSocket.CleanContent || msg.Author.IsBot) return; var guild = gChannel.Guild;
var guild = Boyfriend.FindGuild(channel.Id);
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild.Id);
var isLimitedSpace = msg.CleanContent.Length + messageSocket.CleanContent.Length < 1940; var isLimitedSpace = msg.CleanContent.Length + messageSocket.CleanContent.Length < 1940;
@ -98,10 +93,13 @@ public static class EventHandler {
private static async Task UserJoinedEvent(SocketGuildUser user) { private static async Task UserJoinedEvent(SocketGuildUser user) {
var guild = user.Guild; var guild = user.Guild;
var config = Boyfriend.GetGuildConfig(guild.Id); var config = Boyfriend.GetGuildConfig(guild.Id);
Utils.SetCurrentLanguage(guild.Id);
if (config["SendWelcomeMessages"] is "true") if (config["SendWelcomeMessages"] is "true")
await Utils.SilentSendAsync(guild.SystemChannel, await Utils.SilentSendAsync(guild.SystemChannel,
string.Format(config["WelcomeMessage"], user.Mention, guild.Name)); config["WelcomeMessage"] is "default"
? Messages.DefaultWelcomeMessage
: string.Format(config["WelcomeMessage"], user.Mention, guild.Name));
if (config["StarterRole"] is not "0") await user.AddRoleAsync(ulong.Parse(config["StarterRole"])); if (config["StarterRole"] is not "0") await user.AddRoleAsync(ulong.Parse(config["StarterRole"]));
} }
@ -109,34 +107,35 @@ public static class EventHandler {
private static async Task ScheduledEventCreatedEvent(SocketGuildEvent scheduledEvent) { private static async Task ScheduledEventCreatedEvent(SocketGuildEvent scheduledEvent) {
var guild = scheduledEvent.Guild; var guild = scheduledEvent.Guild;
var eventConfig = Boyfriend.GetGuildConfig(guild.Id); var eventConfig = Boyfriend.GetGuildConfig(guild.Id);
var channel = guild.GetTextChannel(Convert.ToUInt64(eventConfig["EventCreatedChannel"])); var channel = Utils.GetEventNotificationChannel(guild);
if (channel != null) { if (channel is not null) {
var roleMention = ""; var role = guild.GetRole(ulong.Parse(eventConfig["EventNotificationRole"]));
var role = guild.GetRole(Convert.ToUInt64(eventConfig["EventNotifyReceiverRole"])); var mentions = role is not null
if (role != null) roleMention = $"{role.Mention} "; ? $"{role.Mention} {scheduledEvent.Creator.Mention}"
: "{scheduledEvent.Creator.Mention}";
var location = Utils.Wrap(scheduledEvent.Location) ?? Utils.MentionChannel(scheduledEvent.Channel.Id); var location = Utils.Wrap(scheduledEvent.Location) ?? Utils.MentionChannel(scheduledEvent.Channel.Id);
var descAndLink
= $"{Utils.Wrap(scheduledEvent.Description)}\nhttps://discord.com/events/{guild.Id}/{scheduledEvent.Id}";
await Utils.SilentSendAsync(channel, await Utils.SilentSendAsync(channel,
string.Format(Messages.EventCreated, "\n", roleMention, scheduledEvent.Creator.Mention, string.Format(Messages.EventCreated, mentions,
Utils.Wrap(scheduledEvent.Name), location, Utils.Wrap(scheduledEvent.Name), location,
scheduledEvent.StartTime.ToUnixTimeSeconds().ToString(), Utils.Wrap(scheduledEvent.Description), scheduledEvent.StartTime.ToUnixTimeSeconds().ToString(), descAndLink),
guild.Id, scheduledEvent.Id),
true); true);
} }
if (eventConfig["EventEarlyNotificationOffset"] != "0") { if (eventConfig["EventEarlyNotificationOffset"] is not "0")
_ = Utils.SendEarlyEventStartNotificationAsync(channel, scheduledEvent, _ = Utils.SendEarlyEventStartNotificationAsync(channel, scheduledEvent,
Convert.ToInt32(eventConfig["EventEarlyNotificationOffset"])); int.Parse(eventConfig["EventEarlyNotificationOffset"]));
}
} }
private static async Task ScheduledEventCancelledEvent(SocketGuildEvent scheduledEvent) { private static async Task ScheduledEventCancelledEvent(SocketGuildEvent scheduledEvent) {
var guild = scheduledEvent.Guild; var guild = scheduledEvent.Guild;
var eventConfig = Boyfriend.GetGuildConfig(guild.Id); var eventConfig = Boyfriend.GetGuildConfig(guild.Id);
var channel = guild.GetTextChannel(Convert.ToUInt64(eventConfig["EventCancelledChannel"])); var channel = Utils.GetEventNotificationChannel(guild);
if (channel != null) if (channel is not null)
await channel.SendMessageAsync(string.Format(Messages.EventCancelled, Utils.Wrap(scheduledEvent.Name), await channel.SendMessageAsync(string.Format(Messages.EventCancelled, Utils.Wrap(scheduledEvent.Name),
eventConfig["FrowningFace"] is "true" ? $" {Messages.SettingsFrowningFace}" : "")); eventConfig["FrowningFace"] is "true" ? $" {Messages.SettingsFrowningFace}" : ""));
} }
@ -144,14 +143,14 @@ public static class EventHandler {
private static async Task ScheduledEventStartedEvent(SocketGuildEvent scheduledEvent) { private static async Task ScheduledEventStartedEvent(SocketGuildEvent scheduledEvent) {
var guild = scheduledEvent.Guild; var guild = scheduledEvent.Guild;
var eventConfig = Boyfriend.GetGuildConfig(guild.Id); var eventConfig = Boyfriend.GetGuildConfig(guild.Id);
var channel = guild.GetTextChannel(Convert.ToUInt64(eventConfig["EventStartedChannel"])); var channel = Utils.GetEventNotificationChannel(guild);
if (channel != null) { if (channel is not null) {
var receivers = eventConfig["EventStartedReceivers"]; var receivers = eventConfig["EventStartedReceivers"];
var role = guild.GetRole(Convert.ToUInt64(eventConfig["EventNotifyReceiverRole"])); var role = guild.GetRole(ulong.Parse(eventConfig["EventNotificationRole"]));
var mentions = Boyfriend.StringBuilder; var mentions = Boyfriend.StringBuilder;
if (receivers.Contains("role") && role != null) mentions.Append($"{role.Mention} "); if (receivers.Contains("role") && role is not null) mentions.Append($"{role.Mention} ");
if (receivers.Contains("users") || receivers.Contains("interested")) if (receivers.Contains("users") || receivers.Contains("interested"))
mentions = (await scheduledEvent.GetUsersAsync(15)).Aggregate(mentions, mentions = (await scheduledEvent.GetUsersAsync(15)).Aggregate(mentions,
(current, user) => current.Append($"{user.Mention} ")); (current, user) => current.Append($"{user.Mention} "));
@ -165,10 +164,9 @@ public static class EventHandler {
private static async Task ScheduledEventCompletedEvent(SocketGuildEvent scheduledEvent) { private static async Task ScheduledEventCompletedEvent(SocketGuildEvent scheduledEvent) {
var guild = scheduledEvent.Guild; var guild = scheduledEvent.Guild;
var eventConfig = Boyfriend.GetGuildConfig(guild.Id); var channel = Utils.GetEventNotificationChannel(guild);
var channel = guild.GetTextChannel(Convert.ToUInt64(eventConfig["EventCompletedChannel"])); if (channel is not null)
if (channel != null)
await channel.SendMessageAsync(string.Format(Messages.EventCompleted, Utils.Wrap(scheduledEvent.Name), await channel.SendMessageAsync(string.Format(Messages.EventCompleted, Utils.Wrap(scheduledEvent.Name),
Utils.Wrap(scheduledEvent.StartTime.Subtract(DateTimeOffset.Now).Negate().Humanize()))); Utils.GetHumanizedTimeOffset(DateTimeOffset.Now.Subtract(scheduledEvent.StartTime))));
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -25,14 +25,11 @@
</value> </value>
</resheader> </resheader>
<data name="Ready" xml:space="preserve"> <data name="Ready" xml:space="preserve">
<value>{0}I'm ready! (C#)</value> <value>{0}I'm ready!</value>
</data> </data>
<data name="CachedMessageDeleted" xml:space="preserve"> <data name="CachedMessageDeleted" xml:space="preserve">
<value>Deleted message from {0} in channel {1}: {2}</value> <value>Deleted message from {0} in channel {1}: {2}</value>
</data> </data>
<data name="AutobanReason" xml:space="preserve">
<value>Too many mentions in 1 message</value>
</data>
<data name="CachedMessageEdited" xml:space="preserve"> <data name="CachedMessageEdited" xml:space="preserve">
<value>Edited message in channel {0}: {1} -&gt; {2}</value> <value>Edited message in channel {0}: {1} -&gt; {2}</value>
</data> </data>
@ -166,7 +163,7 @@
<value>I cannot use time-outs on other bots! Try to set a mute role in settings</value> <value>I cannot use time-outs on other bots! Try to set a mute role in settings</value>
</data> </data>
<data name="EventCreated" xml:space="preserve"> <data name="EventCreated" xml:space="preserve">
<value>{1}{2} created event {3}! It will take place in {4} and will start &lt;t:{5}:R&gt;!{0}{6}{0}https://discord.com/events/{7}/{8}</value> <value>{0} has created event {1}! It will take place in {2} and will start &lt;t:{3}:R&gt;!\n{4}</value>
</data> </data>
<data name="SettingsEventNotifyReceiverRole" xml:space="preserve"> <data name="SettingsEventNotifyReceiverRole" xml:space="preserve">
<value>Role for event creation notifications</value> <value>Role for event creation notifications</value>
@ -198,9 +195,6 @@
<data name="EventCompleted" xml:space="preserve"> <data name="EventCompleted" xml:space="preserve">
<value>Event {0} has completed! Duration: {1}</value> <value>Event {0} has completed! Duration: {1}</value>
</data> </data>
<data name="FeedbackFormat" xml:space="preserve">
<value>*[{0}: {1}]*</value>
</data>
<data name="Ever" xml:space="preserve"> <data name="Ever" xml:space="preserve">
<value>ever</value> <value>ever</value>
</data> </data>
@ -378,12 +372,6 @@
<data name="UserCannotUnmuteTarget" xml:space="preserve"> <data name="UserCannotUnmuteTarget" xml:space="preserve">
<value>You cannot unmute this user!</value> <value>You cannot unmute this user!</value>
</data> </data>
<data name="CommandDescriptionCavepleaselisten" xml:space="preserve">
<value>We do not support hate towards our fellow members. And sometimes, we are not able to ban the offender.</value>
</data>
<data name="ServerBlacklisted" xml:space="preserve">
<value>This feature is unavailable because this guild is currently blacklisted.</value>
</data>
<data name="EventEarlyNotification" xml:space="preserve"> <data name="EventEarlyNotification" xml:space="preserve">
<value>{0}Event {1} will start &lt;t:{2}:R&gt;!</value> <value>{0}Event {1} will start &lt;t:{2}:R&gt;!</value>
</data> </data>

View file

@ -16,14 +16,11 @@
</value> </value>
</resheader> </resheader>
<data name="Ready" xml:space="preserve"> <data name="Ready" xml:space="preserve">
<value>{0}Я запустился! (C#)</value> <value>{0}Я запустился!</value>
</data> </data>
<data name="CachedMessageDeleted" xml:space="preserve"> <data name="CachedMessageDeleted" xml:space="preserve">
<value>Удалено сообщение от {0} в канале {1}: {2}</value> <value>Удалено сообщение от {0} в канале {1}: {2}</value>
</data> </data>
<data name="AutobanReason" xml:space="preserve">
<value>Слишком много упоминаний в одном сообщении</value>
</data>
<data name="CachedMessageEdited" xml:space="preserve"> <data name="CachedMessageEdited" xml:space="preserve">
<value>Отредактировано сообщение в канале {0}: {1} -&gt; {2}</value> <value>Отредактировано сообщение в канале {0}: {1} -&gt; {2}</value>
</data> </data>
@ -157,7 +154,7 @@
<value>Начальная роль</value> <value>Начальная роль</value>
</data> </data>
<data name="EventCreated" xml:space="preserve"> <data name="EventCreated" xml:space="preserve">
<value>{1}{2} создал событие {3}! Оно пройдёт в {4} и начнётся &lt;t:{5}:R&gt;!{0}{6}{0}https://discord.com/events/{7}/{8}</value> <value>{0} создал событие {1}! Оно пройдёт в {2} и начнётся &lt;t:{3}:R&gt;!\n{4}</value>
</data> </data>
<data name="SettingsEventNotifyReceiverRole" xml:space="preserve"> <data name="SettingsEventNotifyReceiverRole" xml:space="preserve">
<value>Роль для уведомлений о создании событий</value> <value>Роль для уведомлений о создании событий</value>
@ -189,9 +186,6 @@
<data name="EventCompleted" xml:space="preserve"> <data name="EventCompleted" xml:space="preserve">
<value>Событие {0} завершено! Продолжительность: {1}</value> <value>Событие {0} завершено! Продолжительность: {1}</value>
</data> </data>
<data name="FeedbackFormat" xml:space="preserve">
<value>*[{0}: {1}]* </value>
</data>
<data name="Ever" xml:space="preserve"> <data name="Ever" xml:space="preserve">
<value>всегда</value> <value>всегда</value>
</data> </data>
@ -369,12 +363,6 @@
<data name="BotCannotUnmuteTarget" xml:space="preserve"> <data name="BotCannotUnmuteTarget" xml:space="preserve">
<value>Я не могу вернуть из мута этого пользователя!</value> <value>Я не могу вернуть из мута этого пользователя!</value>
</data> </data>
<data name="CommandDescriptionCavepleaselisten" xml:space="preserve">
<value>Мы не поддерживаем ненависть против участников. И иногда, мы не способны забанить нарушителя.</value>
</data>
<data name="ServerBlacklisted" xml:space="preserve">
<value>Эта функция недоступна потому что этот сервер находится в чёрном списке.</value>
</data>
<data name="EventEarlyNotification" xml:space="preserve"> <data name="EventEarlyNotification" xml:space="preserve">
<value>{0}Событие {1} начнется &lt;t:{2}:R&gt;!</value> <value>{0}Событие {1} начнется &lt;t:{2}:R&gt;!</value>
</data> </data>

View file

@ -6,20 +6,21 @@
<value>1.3</value> <value>1.3</value>
</resheader> </resheader>
<resheader name="reader"> <resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader> </resheader>
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader> </resheader>
<data name="Ready" xml:space="preserve"> <data name="Ready" xml:space="preserve">
<value>{0}я родился! (C#)</value> <value>{0}я родился!</value>
</data> </data>
<data name="CachedMessageDeleted" xml:space="preserve"> <data name="CachedMessageDeleted" xml:space="preserve">
<value>вырезано {0} в канале {1}: {2}</value> <value>вырезано {0} в канале {1}: {2}</value>
</data> </data>
<data name="AutobanReason" xml:space="preserve">
<value>ты тут распинался сильно, иди отдохни.</value>
</data>
<data name="CachedMessageEdited" xml:space="preserve"> <data name="CachedMessageEdited" xml:space="preserve">
<value>переделано {0}: {1} -&gt; {2}</value> <value>переделано {0}: {1} -&gt; {2}</value>
</data> </data>
@ -153,7 +154,7 @@
<value>базовое звание</value> <value>базовое звание</value>
</data> </data>
<data name="EventCreated" xml:space="preserve"> <data name="EventCreated" xml:space="preserve">
<value>{1}{2} приготовил новый квест {3}! он пройдёт в {4} и начнётся &lt;t:{5}:R&gt;!{0}{6}{0}https://discord.com/events/{7}/{8}</value> <value>{0} приготовил новый квест {1}! он пройдёт в {2} и начнётся &lt;t:{3}:R&gt;!\n{4}</value>
</data> </data>
<data name="SettingsEventNotifyReceiverRole" xml:space="preserve"> <data name="SettingsEventNotifyReceiverRole" xml:space="preserve">
<value>роль для уведомлений о создании квеста</value> <value>роль для уведомлений о создании квеста</value>
@ -185,9 +186,6 @@
<data name="EventCompleted" xml:space="preserve"> <data name="EventCompleted" xml:space="preserve">
<value>квест {0} завершен! все это длилось {1}</value> <value>квест {0} завершен! все это длилось {1}</value>
</data> </data>
<data name="FeedbackFormat" xml:space="preserve">
<value>*[{0}: {1}]* </value>
</data>
<data name="Ever" xml:space="preserve"> <data name="Ever" xml:space="preserve">
<value>всегда</value> <value>всегда</value>
</data> </data>
@ -365,12 +363,6 @@
<data name="BotCannotUnmuteTarget" xml:space="preserve"> <data name="BotCannotUnmuteTarget" xml:space="preserve">
<value>я не могу его раззамутить...</value> <value>я не могу его раззамутить...</value>
</data> </data>
<data name="CommandDescriptionCavepleaselisten" xml:space="preserve">
<value>каве пропал.</value>
</data>
<data name="ServerBlacklisted" xml:space="preserve">
<value>упс, кажется ваш сервер в черном списке, и я вам ничем помочь не смогу)</value>
</data>
<data name="EventEarlyNotification" xml:space="preserve"> <data name="EventEarlyNotification" xml:space="preserve">
<value>{0}квест {1} начнется &lt;t:{2}:R&gt;!</value> <value>{0}квест {1} начнется &lt;t:{2}:R&gt;!</value>
</data> </data>

View file

@ -12,10 +12,9 @@ using Humanizer.Localisation;
namespace Boyfriend; namespace Boyfriend;
public static class Utils { public static class Utils {
public static readonly Random Random = new();
private static readonly Dictionary<string, string> ReflectionMessageCache = new(); private static readonly Dictionary<string, string> ReflectionMessageCache = new();
private static readonly Dictionary<string, CultureInfo> CultureInfoCache = new() { public static readonly Dictionary<string, CultureInfo> CultureInfoCache = new() {
{ "ru", new CultureInfo("ru-RU") }, { "ru", new CultureInfo("ru-RU") },
{ "en", new CultureInfo("en-US") }, { "en", new CultureInfo("en-US") },
{ "mctaylors-ru", new CultureInfo("tt-RU") } { "mctaylors-ru", new CultureInfo("tt-RU") }
@ -28,16 +27,16 @@ public static class Utils {
}; };
public static string GetBeep(int i = -1) { public static string GetBeep(int i = -1) {
return GetMessage($"Beep{(i < 0 ? Random.Next(3) + 1 : ++i)}"); return GetMessage($"Beep{(i < 0 ? Random.Shared.Next(3) + 1 : ++i)}");
} }
public static SocketTextChannel? GetAdminLogChannel(ulong id) { public static SocketTextChannel? GetBotLogChannel(ulong id) {
return Boyfriend.Client.GetGuild(id) return Boyfriend.Client.GetGuild(id)
.GetTextChannel(ParseMention(Boyfriend.GetGuildConfig(id)["AdminLogChannel"])); .GetTextChannel(ParseMention(Boyfriend.GetGuildConfig(id)["BotLogChannel"]));
} }
public static string? Wrap(string? original, bool limitedSpace = false) { public static string? Wrap(string? original, bool limitedSpace = false) {
if (original == null) return null; if (original is null) return null;
var maxChars = limitedSpace ? 970 : 1940; var maxChars = limitedSpace ? 970 : 1940;
if (original.Length > maxChars) original = original[..maxChars]; if (original.Length > maxChars) original = original[..maxChars];
var style = original.Contains('\n') ? "```" : "`"; var style = original.Contains('\n') ? "```" : "`";
@ -52,29 +51,22 @@ public static class Utils {
return ulong.TryParse(Regex.Replace(mention, "[^0-9]", ""), out var id) ? id : 0; return ulong.TryParse(Regex.Replace(mention, "[^0-9]", ""), out var id) ? id : 0;
} }
public static SocketUser? ParseUser(string mention) {
var user = Boyfriend.Client.GetUser(ParseMention(mention));
return user;
}
public static async Task SendDirectMessage(SocketUser user, string toSend) { public static async Task SendDirectMessage(SocketUser user, string toSend) {
try { await user.SendMessageAsync(toSend); } catch (HttpException e) { try { await user.SendMessageAsync(toSend); } catch (HttpException e) {
if (e.DiscordCode != DiscordErrorCode.CannotSendMessageToUser) throw; if (e.DiscordCode is not DiscordErrorCode.CannotSendMessageToUser) throw;
} }
} }
public static SocketRole? GetMuteRole(SocketGuild guild) { public static SocketRole? GetMuteRole(SocketGuild guild) {
var id = ulong.Parse(Boyfriend.GetGuildConfig(guild.Id)["MuteRole"]); var id = ulong.Parse(Boyfriend.GetGuildConfig(guild.Id)["MuteRole"]);
if (MuteRoleCache.TryGetValue(id, out var cachedMuteRole)) return cachedMuteRole; if (MuteRoleCache.TryGetValue(id, out var cachedMuteRole)) return cachedMuteRole;
SocketRole? role = null;
foreach (var x in guild.Roles) { foreach (var x in guild.Roles) {
if (x.Id != id) continue; if (x.Id != id) continue;
role = x; MuteRoleCache.Add(id, x);
MuteRoleCache.Add(id, role); return x;
break;
} }
return role; return null;
} }
public static void RemoveMuteRoleFromCache(ulong id) { public static void RemoveMuteRoleFromCache(ulong id) {
@ -82,7 +74,7 @@ public static class Utils {
} }
public static async Task SilentSendAsync(SocketTextChannel? channel, string text, bool allowRoles = false) { public static async Task SilentSendAsync(SocketTextChannel? channel, string text, bool allowRoles = false) {
if (channel == null || text.Length is 0 or > 2000) if (channel is null || text.Length is 0 or > 2000)
throw new Exception($"Message length is out of range: {text.Length}"); throw new Exception($"Message length is out of range: {text.Length}");
await channel.SendMessageAsync(text, false, null, null, allowRoles ? AllowRoles : AllowedMentions.None); await channel.SendMessageAsync(text, false, null, null, allowRoles ? AllowRoles : AllowedMentions.None);
@ -102,8 +94,8 @@ public static class Utils {
var toReturn = var toReturn =
typeof(Messages).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null) typeof(Messages).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null)
?.ToString(); ?.ToString();
if (toReturn == null) { if (toReturn is null) {
Console.WriteLine($@"Could not find localized property: {propertyName}"); Console.Error.WriteLine($@"Could not find localized property: {propertyName}");
return name; return name;
} }
@ -113,11 +105,11 @@ public static class Utils {
public static async Task public static async Task
SendFeedbackAsync(string feedback, ulong guildId, string mention, bool sendPublic = false) { SendFeedbackAsync(string feedback, ulong guildId, string mention, bool sendPublic = false) {
var adminChannel = GetAdminLogChannel(guildId); var adminChannel = GetBotLogChannel(guildId);
var systemChannel = Boyfriend.Client.GetGuild(guildId).SystemChannel; var systemChannel = Boyfriend.Client.GetGuild(guildId).SystemChannel;
var toSend = string.Format(Messages.FeedbackFormat, mention, feedback); var toSend = $"*[{mention}: {feedback}]*";
if (adminChannel != null) await SilentSendAsync(adminChannel, toSend); if (adminChannel is not null) await SilentSendAsync(adminChannel, toSend);
if (sendPublic && systemChannel != null) await SilentSendAsync(systemChannel, toSend); if (sendPublic && systemChannel is not null) await SilentSendAsync(systemChannel, toSend);
} }
public static string GetHumanizedTimeOffset(TimeSpan span) { public static string GetHumanizedTimeOffset(TimeSpan span) {
@ -131,7 +123,7 @@ public static class Utils {
} }
public static void SafeAppendToBuilder(StringBuilder appendTo, string appendWhat, SocketTextChannel? channel) { public static void SafeAppendToBuilder(StringBuilder appendTo, string appendWhat, SocketTextChannel? channel) {
if (channel == null) return; if (channel is null) return;
if (appendTo.Length + appendWhat.Length > 2000) { if (appendTo.Length + appendWhat.Length > 2000) {
_ = SilentSendAsync(channel, appendTo.ToString()); _ = SilentSendAsync(channel, appendTo.ToString());
appendTo.Clear(); appendTo.Clear();
@ -169,15 +161,19 @@ public static class Utils {
var eventConfig = Boyfriend.GetGuildConfig(guild.Id); var eventConfig = Boyfriend.GetGuildConfig(guild.Id);
var receivers = eventConfig["EventStartedReceivers"]; var receivers = eventConfig["EventStartedReceivers"];
var role = guild.GetRole(Convert.ToUInt64(eventConfig["EventNotifyReceiverRole"])); var role = guild.GetRole(ulong.Parse(eventConfig["EventNotificationRole"]));
var mentions = Boyfriend.StringBuilder; var mentions = Boyfriend.StringBuilder;
if (receivers.Contains("role") && role != null) mentions.Append($"{role.Mention} "); if (receivers.Contains("role") && role is not null) mentions.Append($"{role.Mention} ");
if (receivers.Contains("users") || receivers.Contains("interested")) if (receivers.Contains("users") || receivers.Contains("interested"))
mentions = (await scheduledEvent.GetUsersAsync(15)).Aggregate(mentions, mentions = (await scheduledEvent.GetUsersAsync(15)).Aggregate(mentions,
(current, user) => current.Append($"{user.Mention} ")); (current, user) => current.Append($"{user.Mention} "));
await channel?.SendMessageAsync(string.Format(Messages.EventEarlyNotification, mentions, await channel?.SendMessageAsync(string.Format(Messages.EventEarlyNotification, mentions,
Wrap(scheduledEvent.Name), scheduledEvent.StartTime.ToUnixTimeSeconds()))!; Wrap(scheduledEvent.Name), scheduledEvent.StartTime.ToUnixTimeSeconds().ToString()))!;
mentions.Clear(); mentions.Clear();
} }
public static SocketTextChannel? GetEventNotificationChannel(SocketGuild guild) {
return guild.GetTextChannel(ParseMention(Boyfriend.GetGuildConfig(guild.Id)["EventCreatedChannel"]));
}
} }