1
0
Fork 1
mirror of https://github.com/TeamOctolings/Octobot.git synced 2025-01-31 09:09:00 +03:00

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 readonly StringBuilder StringBuilder = new();
private static readonly Dictionary<ulong, SocketGuild> GuildCache = new();
private static readonly DiscordSocketConfig Config = new() {
MessageCacheSize = 250,
GatewayIntents = GatewayIntents.All,
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.MessageContent | GatewayIntents.GuildMembers,
AlwaysDownloadUsers = true,
AlwaysResolveStickers = false,
AlwaysDownloadDefaultStickers = false,
@ -37,23 +36,20 @@ public static class Boyfriend {
new();
public static readonly Dictionary<string, string> DefaultConfig = new() {
{ "Lang", "en" },
{ "Prefix", "!" },
{ "RemoveRolesOnMute", "false" },
{ "SendWelcomeMessages", "true" },
{ "Lang", "en" },
{ "ReceiveStartupMessages", "false" },
{ "FrowningFace", "true" },
{ "WelcomeMessage", Messages.DefaultWelcomeMessage },
{ "EventStartedReceivers", "interested,role" },
{ "WelcomeMessage", "default" },
{ "SendWelcomeMessages", "true" },
{ "BotLogChannel", "0" },
{ "StarterRole", "0" },
{ "MuteRole", "0" },
{ "EventNotifyReceiverRole", "0" },
{ "AdminLogChannel", "0" },
{ "BotLogChannel", "0" },
{ "EventCreatedChannel", "0" },
{ "EventStartedChannel", "0" },
{ "EventCancelledChannel", "0" },
{ "EventCompletedChannel", "0" },
{ "RemoveRolesOnMute", "false" },
{ "FrowningFace", "true" },
{ "EventStartedReceivers", "interested,role" },
{ "EventNotificationRole", "0" },
{ "EventNotificationChannel", "0" },
{ "EventEarlyNotificationOffset", "0" }
};
@ -81,8 +77,29 @@ public static class Boyfriend {
}
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());
break;
case LogSeverity.Info:
Console.WriteLine(msg.ToString());
break;
case LogSeverity.Verbose:
case LogSeverity.Debug:
default: return Task.CompletedTask;
}
Console.ResetColor();
return Task.CompletedTask;
}
@ -95,9 +112,6 @@ public static class Boyfriend {
}
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;
var path = $"config_{id}.json";
@ -110,13 +124,12 @@ public static class Boyfriend {
if (config.Keys.Count < DefaultConfig.Keys.Count) {
// 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)
if (!config.ContainsKey(key))
config.Add(key, DefaultConfig[key]);
} else if (config.Keys.Count > DefaultConfig.Keys.Count) {
foreach (var key in config.Keys.Where(key => !DefaultConfig.ContainsKey(key)))
config.Remove(key);
foreach (var key in config.Keys.Where(key => !DefaultConfig.ContainsKey(key))) config.Remove(key);
}
GuildConfigDictionary.Add(id, config);
@ -126,10 +139,9 @@ public static class Boyfriend {
public static Dictionary<ulong, ReadOnlyCollection<ulong>> GetRemovedRoles(ulong id) {
if (RemovedRolesDictionary.TryGetValue(id, out var dict)) return dict;
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 removedRoles = JsonConvert.DeserializeObject<Dictionary<ulong, ReadOnlyCollection<ulong>>>(json)
@ -139,18 +151,4 @@ public static class Boyfriend {
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();
public readonly SocketCommandContext Context;
private bool _serverBlacklisted;
public bool ConfigWriteScheduled = false;
@ -39,6 +38,7 @@ public sealed class CommandProcessor {
var guild = Context.Guild;
var config = Boyfriend.GetGuildConfig(guild.Id);
var muteRole = Utils.GetMuteRole(guild);
Utils.SetCurrentLanguage(guild.Id);
if (GetMember().Roles.Contains(muteRole)) {
await Context.Message.ReplyAsync(Messages.UserCannotUnmuteThemselves);
@ -49,15 +49,11 @@ public sealed class CommandProcessor {
var cleanList = Context.Message.CleanContent.Split("\n");
for (var i = 0; i < list.Length; i++) {
RunCommandOnLine(list[i], cleanList[i], config["Prefix"]);
if (_serverBlacklisted) {
await Context.Message.ReplyAsync(Messages.ServerBlacklisted);
return;
}
if (_stackedReplyMessage.Length > 0) _ = Context.Channel.TriggerTypingAsync();
var member = Boyfriend.Client.GetGuild(Context.Guild.Id)
.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() >
DateTimeOffset.Now.ToUnixTimeSeconds()) break;
}
@ -89,25 +85,25 @@ public sealed class CommandProcessor {
}
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);
Utils.SafeAppendToBuilder(_stackedPrivateFeedback, format, Utils.GetAdminLogChannel(Context.Guild.Id));
if (_tasks.Count == 0) SendFeedbacks(false);
Utils.SafeAppendToBuilder(_stackedPrivateFeedback, format, Utils.GetBotLogChannel(Context.Guild.Id));
if (_tasks.Count is 0) SendFeedbacks(false);
}
private void SendFeedbacks(bool reply = true) {
if (reply && _stackedReplyMessage.Length > 0)
_ = 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;
if (_stackedPrivateFeedback.Length > 0 && adminChannel != null &&
if (_stackedPrivateFeedback.Length > 0 && adminChannel is not null &&
adminChannel.Id != Context.Message.Channel.Id) {
_ = Utils.SilentSendAsync(adminChannel, _stackedPrivateFeedback.ToString());
_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) {
_ = Utils.SilentSendAsync(systemChannel, _stackedPublicFeedback.ToString());
_stackedPublicFeedback.Clear();
@ -115,7 +111,7 @@ public sealed class CommandProcessor {
}
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,
$"{MissingArgument}{Utils.GetMessage($"Missing{argument}")}", Context.Message);
else return string.Join(" ", from, startIndex, from.Length - startIndex);
@ -129,8 +125,8 @@ public sealed class CommandProcessor {
return null;
}
var user = Utils.ParseUser(args[index]);
if (user == null && argument != null)
var user = Boyfriend.Client.GetUser(Utils.ParseMention(args[index]));
if (user is null && argument is not null)
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{InvalidArgument}{string.Format(Messages.InvalidUser, Utils.Wrap(cleanArgs[index]))}",
Context.Message);
@ -154,7 +150,7 @@ public sealed class CommandProcessor {
public SocketGuildUser? GetMember(SocketUser user, string? argument) {
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);
return member;
}
@ -167,7 +163,7 @@ public sealed class CommandProcessor {
}
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,
$"{InvalidArgument}{string.Format(Messages.InvalidMember, Utils.Wrap(cleanArgs[index]))}",
Context.Message);
@ -186,7 +182,7 @@ public sealed class CommandProcessor {
}
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);
return null;
}
@ -209,7 +205,7 @@ public sealed class CommandProcessor {
return null;
}
if (argument == null) return i;
if (argument is null) return i;
if (i < min) {
Utils.SafeAppendToBuilder(_stackedReplyMessage,
$"{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;
foreach (var c in chars)
if (char.IsDigit(c)) { numberBuilder.Append(c); } else {
if (numberBuilder.Length == 0) return infinity;
if (numberBuilder.Length is 0) return infinity;
switch (c) {
case 'd' or 'D' or 'д' or 'Д':
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) {
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);
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 reason = cmd.GetRemaining(args, duration.TotalSeconds < 1 ? 1 : 2, "BanReason");
if (reason == null) return;
await BanUser(cmd, toBan, duration, reason);
if (reason is not null) await BanUserAsync(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 guild = cmd.Context.Guild;
await Utils.SendDirectMessage(toBan,

View file

@ -12,7 +12,7 @@ public sealed class ClearCommand : ICommand {
if (!cmd.HasPermission(GuildPermission.ManageMessages)) return;
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 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) {
var toKick = cmd.GetMember(args, cleanArgs, 0, "ToKick");
if (toKick == null || !cmd.HasPermission(GuildPermission.KickMembers)) return;
if (!cmd.CanInteractWith(toKick, "Kick")) return;
if (toKick is null || !cmd.HasPermission(GuildPermission.KickMembers)) return;
if (cmd.CanInteractWith(toKick, "Kick"))
await KickMemberAsync(cmd, toKick, cmd.GetRemaining(args, 1, "KickReason"));
}
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}";
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) {
var toMute = cmd.GetMember(args, cleanArgs, 0, "ToMute");
if (toMute == null) return;
if (toMute is null) return;
var duration = CommandProcessor.GetTimeSpan(args, 1);
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);
if ((role != null && toMute.Roles.Contains(role))
|| (toMute.TimedOutUntil != null
if ((role is not null && toMute.Roles.Contains(role))
|| (toMute.TimedOutUntil is not null
&& toMute.TimedOutUntil.Value.ToUnixTimeSeconds()
> DateTimeOffset.Now.ToUnixTimeSeconds())) {
cmd.Reply(Messages.MemberAlreadyMuted, ":x: ");
@ -33,8 +33,7 @@ public sealed class MuteCommand : ICommand {
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);
}
@ -46,7 +45,7 @@ public sealed class MuteCommand : ICommand {
var role = Utils.GetMuteRole(guild);
var hasDuration = duration.TotalSeconds > 0;
if (role != null) {
if (role is not null) {
if (config["RemoveRolesOnMute"] is "true") {
var rolesRemoved = new List<ulong>();
foreach (var userRole in toMute.Roles)

View file

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

View file

@ -9,11 +9,9 @@ public sealed class UnbanCommand : ICommand {
if (!cmd.HasPermission(GuildPermission.BanMembers)) return;
var id = cmd.GetBan(args, 0);
if (id == null) return;
if (id is null) return;
var reason = cmd.GetRemaining(args, 1, "UnbanReason");
if (reason == null) return;
await UnbanUserAsync(cmd, id.Value, reason);
if (reason is not null) await UnbanUserAsync(cmd, id.Value, 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;
var toUnmute = cmd.GetMember(args, cleanArgs, 0, "ToUnmute");
if (toUnmute is null) return;
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);
}
@ -20,7 +21,7 @@ public sealed class UnmuteCommand : ICommand {
var requestOptions = Utils.GetRequestOptions($"({cmd.Context.User}) {reason}");
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);
if (rolesRemoved.TryGetValue(toUnmute.Id, out var unmutedRemovedRoles)) {
@ -31,7 +32,7 @@ public sealed class UnmuteCommand : ICommand {
await toUnmute.RemoveRoleAsync(role, requestOptions);
} else {
if (toUnmute.TimedOutUntil == null || toUnmute.TimedOutUntil.Value.ToUnixTimeSeconds() <
if (toUnmute.TimedOutUntil is null || toUnmute.TimedOutUntil.Value.ToUnixTimeSeconds() <
DateTimeOffset.Now.ToUnixTimeSeconds()) {
cmd.Reply(Messages.MemberNotMuted, ":x: ");
return;

View file

@ -1,7 +1,6 @@
using Discord;
using Discord.Rest;
using Discord.WebSocket;
using Humanizer;
namespace Boyfriend;
@ -23,14 +22,14 @@ public static class EventHandler {
private static Task ReadyEvent() {
if (!_sendReadyMessages) return Task.CompletedTask;
var i = Utils.Random.Next(3);
var i = Random.Shared.Next(3);
foreach (var guild in Client.Guilds) {
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);
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)));
}
@ -41,9 +40,10 @@ public static class EventHandler {
private static async Task MessageDeletedEvent(Cacheable<IMessage, ulong> message,
Cacheable<IMessageChannel, ulong> channel) {
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);
@ -61,11 +61,7 @@ public static class EventHandler {
}
private static Task MessageReceivedEvent(SocketMessage messageParam) {
if (messageParam is not SocketUserMessage { Author: SocketGuildUser user } message) return Task.CompletedTask;
var guild = user.Guild;
Utils.SetCurrentLanguage(guild.Id);
if (messageParam is not SocketUserMessage message) return Task.CompletedTask;
_ = message.CleanContent.ToLower() switch {
"whoami" => message.ReplyAsync("`nobody`"),
@ -81,11 +77,10 @@ public static class EventHandler {
private static async Task MessageUpdatedEvent(Cacheable<IMessage, ulong> messageCached, SocketMessage messageSocket,
ISocketMessageChannel channel) {
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 = Boyfriend.FindGuild(channel.Id);
var guild = gChannel.Guild;
Utils.SetCurrentLanguage(guild.Id);
var isLimitedSpace = msg.CleanContent.Length + messageSocket.CleanContent.Length < 1940;
@ -98,10 +93,13 @@ public static class EventHandler {
private static async Task UserJoinedEvent(SocketGuildUser user) {
var guild = user.Guild;
var config = Boyfriend.GetGuildConfig(guild.Id);
Utils.SetCurrentLanguage(guild.Id);
if (config["SendWelcomeMessages"] is "true")
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"]));
}
@ -109,34 +107,35 @@ public static class EventHandler {
private static async Task ScheduledEventCreatedEvent(SocketGuildEvent scheduledEvent) {
var guild = scheduledEvent.Guild;
var eventConfig = Boyfriend.GetGuildConfig(guild.Id);
var channel = guild.GetTextChannel(Convert.ToUInt64(eventConfig["EventCreatedChannel"]));
var channel = Utils.GetEventNotificationChannel(guild);
if (channel != null) {
var roleMention = "";
var role = guild.GetRole(Convert.ToUInt64(eventConfig["EventNotifyReceiverRole"]));
if (role != null) roleMention = $"{role.Mention} ";
if (channel is not null) {
var role = guild.GetRole(ulong.Parse(eventConfig["EventNotificationRole"]));
var mentions = role is not null
? $"{role.Mention} {scheduledEvent.Creator.Mention}"
: "{scheduledEvent.Creator.Mention}";
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,
string.Format(Messages.EventCreated, "\n", roleMention, scheduledEvent.Creator.Mention,
string.Format(Messages.EventCreated, mentions,
Utils.Wrap(scheduledEvent.Name), location,
scheduledEvent.StartTime.ToUnixTimeSeconds().ToString(), Utils.Wrap(scheduledEvent.Description),
guild.Id, scheduledEvent.Id),
scheduledEvent.StartTime.ToUnixTimeSeconds().ToString(), descAndLink),
true);
}
if (eventConfig["EventEarlyNotificationOffset"] != "0") {
if (eventConfig["EventEarlyNotificationOffset"] is not "0")
_ = Utils.SendEarlyEventStartNotificationAsync(channel, scheduledEvent,
Convert.ToInt32(eventConfig["EventEarlyNotificationOffset"]));
}
int.Parse(eventConfig["EventEarlyNotificationOffset"]));
}
private static async Task ScheduledEventCancelledEvent(SocketGuildEvent scheduledEvent) {
var guild = scheduledEvent.Guild;
var eventConfig = Boyfriend.GetGuildConfig(guild.Id);
var channel = guild.GetTextChannel(Convert.ToUInt64(eventConfig["EventCancelledChannel"]));
if (channel != null)
var channel = Utils.GetEventNotificationChannel(guild);
if (channel is not null)
await channel.SendMessageAsync(string.Format(Messages.EventCancelled, Utils.Wrap(scheduledEvent.Name),
eventConfig["FrowningFace"] is "true" ? $" {Messages.SettingsFrowningFace}" : ""));
}
@ -144,14 +143,14 @@ public static class EventHandler {
private static async Task ScheduledEventStartedEvent(SocketGuildEvent scheduledEvent) {
var guild = scheduledEvent.Guild;
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 role = guild.GetRole(Convert.ToUInt64(eventConfig["EventNotifyReceiverRole"]));
var role = guild.GetRole(ulong.Parse(eventConfig["EventNotificationRole"]));
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"))
mentions = (await scheduledEvent.GetUsersAsync(15)).Aggregate(mentions,
(current, user) => current.Append($"{user.Mention} "));
@ -165,10 +164,9 @@ public static class EventHandler {
private static async Task ScheduledEventCompletedEvent(SocketGuildEvent scheduledEvent) {
var guild = scheduledEvent.Guild;
var eventConfig = Boyfriend.GetGuildConfig(guild.Id);
var channel = guild.GetTextChannel(Convert.ToUInt64(eventConfig["EventCompletedChannel"]));
if (channel != null)
var channel = Utils.GetEventNotificationChannel(guild);
if (channel is not null)
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>
</resheader>
<data name="Ready" xml:space="preserve">
<value>{0}I'm ready! (C#)</value>
<value>{0}I'm ready!</value>
</data>
<data name="CachedMessageDeleted" xml:space="preserve">
<value>Deleted message from {0} in channel {1}: {2}</value>
</data>
<data name="AutobanReason" xml:space="preserve">
<value>Too many mentions in 1 message</value>
</data>
<data name="CachedMessageEdited" xml:space="preserve">
<value>Edited message in channel {0}: {1} -&gt; {2}</value>
</data>
@ -166,7 +163,7 @@
<value>I cannot use time-outs on other bots! Try to set a mute role in settings</value>
</data>
<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 name="SettingsEventNotifyReceiverRole" xml:space="preserve">
<value>Role for event creation notifications</value>
@ -198,9 +195,6 @@
<data name="EventCompleted" xml:space="preserve">
<value>Event {0} has completed! Duration: {1}</value>
</data>
<data name="FeedbackFormat" xml:space="preserve">
<value>*[{0}: {1}]*</value>
</data>
<data name="Ever" xml:space="preserve">
<value>ever</value>
</data>
@ -378,12 +372,6 @@
<data name="UserCannotUnmuteTarget" xml:space="preserve">
<value>You cannot unmute this user!</value>
</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">
<value>{0}Event {1} will start &lt;t:{2}:R&gt;!</value>
</data>

View file

@ -16,14 +16,11 @@
</value>
</resheader>
<data name="Ready" xml:space="preserve">
<value>{0}Я запустился! (C#)</value>
<value>{0}Я запустился!</value>
</data>
<data name="CachedMessageDeleted" xml:space="preserve">
<value>Удалено сообщение от {0} в канале {1}: {2}</value>
</data>
<data name="AutobanReason" xml:space="preserve">
<value>Слишком много упоминаний в одном сообщении</value>
</data>
<data name="CachedMessageEdited" xml:space="preserve">
<value>Отредактировано сообщение в канале {0}: {1} -&gt; {2}</value>
</data>
@ -157,7 +154,7 @@
<value>Начальная роль</value>
</data>
<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 name="SettingsEventNotifyReceiverRole" xml:space="preserve">
<value>Роль для уведомлений о создании событий</value>
@ -189,9 +186,6 @@
<data name="EventCompleted" xml:space="preserve">
<value>Событие {0} завершено! Продолжительность: {1}</value>
</data>
<data name="FeedbackFormat" xml:space="preserve">
<value>*[{0}: {1}]* </value>
</data>
<data name="Ever" xml:space="preserve">
<value>всегда</value>
</data>
@ -369,12 +363,6 @@
<data name="BotCannotUnmuteTarget" xml:space="preserve">
<value>Я не могу вернуть из мута этого пользователя!</value>
</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">
<value>{0}Событие {1} начнется &lt;t:{2}:R&gt;!</value>
</data>

View file

@ -6,20 +6,21 @@
<value>1.3</value>
</resheader>
<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 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>
<data name="Ready" xml:space="preserve">
<value>{0}я родился! (C#)</value>
<value>{0}я родился!</value>
</data>
<data name="CachedMessageDeleted" xml:space="preserve">
<value>вырезано {0} в канале {1}: {2}</value>
</data>
<data name="AutobanReason" xml:space="preserve">
<value>ты тут распинался сильно, иди отдохни.</value>
</data>
<data name="CachedMessageEdited" xml:space="preserve">
<value>переделано {0}: {1} -&gt; {2}</value>
</data>
@ -153,7 +154,7 @@
<value>базовое звание</value>
</data>
<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 name="SettingsEventNotifyReceiverRole" xml:space="preserve">
<value>роль для уведомлений о создании квеста</value>
@ -185,9 +186,6 @@
<data name="EventCompleted" xml:space="preserve">
<value>квест {0} завершен! все это длилось {1}</value>
</data>
<data name="FeedbackFormat" xml:space="preserve">
<value>*[{0}: {1}]* </value>
</data>
<data name="Ever" xml:space="preserve">
<value>всегда</value>
</data>
@ -365,12 +363,6 @@
<data name="BotCannotUnmuteTarget" xml:space="preserve">
<value>я не могу его раззамутить...</value>
</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">
<value>{0}квест {1} начнется &lt;t:{2}:R&gt;!</value>
</data>

View file

@ -12,10 +12,9 @@ using Humanizer.Localisation;
namespace Boyfriend;
public static class Utils {
public static readonly Random Random = 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") },
{ "en", new CultureInfo("en-US") },
{ "mctaylors-ru", new CultureInfo("tt-RU") }
@ -28,16 +27,16 @@ public static class Utils {
};
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)
.GetTextChannel(ParseMention(Boyfriend.GetGuildConfig(id)["AdminLogChannel"]));
.GetTextChannel(ParseMention(Boyfriend.GetGuildConfig(id)["BotLogChannel"]));
}
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;
if (original.Length > maxChars) original = original[..maxChars];
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;
}
public static SocketUser? ParseUser(string mention) {
var user = Boyfriend.Client.GetUser(ParseMention(mention));
return user;
}
public static async Task SendDirectMessage(SocketUser user, string toSend) {
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) {
var id = ulong.Parse(Boyfriend.GetGuildConfig(guild.Id)["MuteRole"]);
if (MuteRoleCache.TryGetValue(id, out var cachedMuteRole)) return cachedMuteRole;
SocketRole? role = null;
foreach (var x in guild.Roles) {
if (x.Id != id) continue;
role = x;
MuteRoleCache.Add(id, role);
break;
MuteRoleCache.Add(id, x);
return x;
}
return role;
return null;
}
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) {
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}");
await channel.SendMessageAsync(text, false, null, null, allowRoles ? AllowRoles : AllowedMentions.None);
@ -102,8 +94,8 @@ public static class Utils {
var toReturn =
typeof(Messages).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null)
?.ToString();
if (toReturn == null) {
Console.WriteLine($@"Could not find localized property: {propertyName}");
if (toReturn is null) {
Console.Error.WriteLine($@"Could not find localized property: {propertyName}");
return name;
}
@ -113,11 +105,11 @@ public static class Utils {
public static async Task
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 toSend = string.Format(Messages.FeedbackFormat, mention, feedback);
if (adminChannel != null) await SilentSendAsync(adminChannel, toSend);
if (sendPublic && systemChannel != null) await SilentSendAsync(systemChannel, toSend);
var toSend = $"*[{mention}: {feedback}]*";
if (adminChannel is not null) await SilentSendAsync(adminChannel, toSend);
if (sendPublic && systemChannel is not null) await SilentSendAsync(systemChannel, toSend);
}
public static string GetHumanizedTimeOffset(TimeSpan span) {
@ -131,7 +123,7 @@ public static class Utils {
}
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) {
_ = SilentSendAsync(channel, appendTo.ToString());
appendTo.Clear();
@ -169,15 +161,19 @@ public static class Utils {
var eventConfig = Boyfriend.GetGuildConfig(guild.Id);
var receivers = eventConfig["EventStartedReceivers"];
var role = guild.GetRole(Convert.ToUInt64(eventConfig["EventNotifyReceiverRole"]));
var role = guild.GetRole(ulong.Parse(eventConfig["EventNotificationRole"]));
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"))
mentions = (await scheduledEvent.GetUsersAsync(15)).Aggregate(mentions,
(current, user) => current.Append($"{user.Mention} "));
await channel?.SendMessageAsync(string.Format(Messages.EventEarlyNotification, mentions,
Wrap(scheduledEvent.Name), scheduledEvent.StartTime.ToUnixTimeSeconds()))!;
Wrap(scheduledEvent.Name), scheduledEvent.StartTime.ToUnixTimeSeconds().ToString()))!;
mentions.Clear();
}
public static SocketTextChannel? GetEventNotificationChannel(SocketGuild guild) {
return guild.GetTextChannel(ParseMention(Boyfriend.GetGuildConfig(guild.Id)["EventCreatedChannel"]));
}
}