1
0
Fork 1
mirror of https://github.com/TeamOctolings/Octobot.git synced 2025-04-20 00:43:36 +03:00

Continue adapting code to new guild data storage

This commit is contained in:
Octol1ttle 2022-12-30 18:34:48 +05:00
parent 163e3ac46b
commit fe2cfb3b3c
Signed by: Octol1ttle
GPG key ID: B77C34313AEE1FFF
10 changed files with 145 additions and 94 deletions

View file

@ -1,5 +1,6 @@
using System.Text; using System.Text;
using Boyfriend.Commands; using Boyfriend.Commands;
using Boyfriend.Data;
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
@ -12,7 +13,8 @@ public sealed class CommandProcessor {
public static readonly ICommand[] Commands = { public static readonly ICommand[] Commands = {
new BanCommand(), new ClearCommand(), new HelpCommand(), new BanCommand(), new ClearCommand(), new HelpCommand(),
new KickCommand(), new MuteCommand(), new PingCommand(), new KickCommand(), new MuteCommand(), new PingCommand(),
new SettingsCommand(), new UnbanCommand(), new UnmuteCommand() new SettingsCommand(), new UnbanCommand(), new UnmuteCommand(),
new RemindCommand()
}; };
private readonly StringBuilder _stackedPrivateFeedback = new(); private readonly StringBuilder _stackedPrivateFeedback = new();
@ -30,11 +32,10 @@ public sealed class CommandProcessor {
public async Task HandleCommandAsync() { public async Task HandleCommandAsync() {
var guild = Context.Guild; var guild = Context.Guild;
var config = Boyfriend.GetGuildConfig(guild.Id); var data = GuildData.FromSocketGuild(guild);
var muteRole = Utils.GetMuteRole(guild); Utils.SetCurrentLanguage(guild);
Utils.SetCurrentLanguage(guild.Id);
if (GetMember().Roles.Contains(muteRole)) { if (GetMember().Roles.Contains(data.MuteRole)) {
_ = Context.Message.ReplyAsync(Messages.UserCannotUnmuteThemselves); _ = Context.Message.ReplyAsync(Messages.UserCannotUnmuteThemselves);
return; return;
} }
@ -42,7 +43,7 @@ public sealed class CommandProcessor {
var list = Context.Message.Content.Split("\n"); var list = Context.Message.Content.Split("\n");
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++)
_tasks.Add(RunCommandOnLine(list[i], cleanList[i], config["Prefix"])); _tasks.Add(RunCommandOnLine(list[i], cleanList[i], data.Preferences["Prefix"]));
try { Task.WaitAll(_tasks.ToArray()); } catch (AggregateException e) { try { Task.WaitAll(_tasks.ToArray()); } catch (AggregateException e) {
foreach (var ex in e.InnerExceptions) foreach (var ex in e.InnerExceptions)
@ -52,7 +53,7 @@ public sealed class CommandProcessor {
_tasks.Clear(); _tasks.Clear();
if (ConfigWriteScheduled) await Boyfriend.WriteGuildConfigAsync(guild.Id); if (ConfigWriteScheduled) await data.Save(true);
SendFeedbacks(); SendFeedbacks();
} }
@ -80,7 +81,7 @@ public sealed class CommandProcessor {
public void Audit(string action, bool isPublic = true) { public void Audit(string action, bool isPublic = true) {
var format = $"*[{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.GetBotLogChannel(Context.Guild.Id)); Utils.SafeAppendToBuilder(_stackedPrivateFeedback, format, Utils.GetBotLogChannel(Context.Guild));
if (_tasks.Count is 0) SendFeedbacks(false); if (_tasks.Count is 0) SendFeedbacks(false);
} }
@ -88,7 +89,7 @@ public sealed class CommandProcessor {
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.GetBotLogChannel(Context.Guild.Id); var adminChannel = Utils.GetBotLogChannel(Context.Guild);
var systemChannel = Context.Guild.SystemChannel; var systemChannel = Context.Guild.SystemChannel;
if (_stackedPrivateFeedback.Length > 0 && adminChannel is not null && if (_stackedPrivateFeedback.Length > 0 && adminChannel is not null &&
adminChannel.Id != Context.Message.Channel.Id) { adminChannel.Id != Context.Message.Channel.Id) {

View file

@ -28,12 +28,14 @@ public sealed class BanCommand : ICommand {
var guildBanMessage = $"({author}) {reason}"; var guildBanMessage = $"({author}) {reason}";
await guild.AddBanAsync(toBan, 0, guildBanMessage); await guild.AddBanAsync(toBan, 0, guildBanMessage);
var memberData = GuildData.FromSocketGuild(guild).MemberData[toBan.Id];
memberData.BannedUntil
= duration.TotalSeconds < 1 ? -1 : DateTimeOffset.Now.Add(duration).ToUnixTimeSeconds();
memberData.Roles.Clear();
var feedback = string.Format(Messages.FeedbackUserBanned, toBan.Mention, var feedback = string.Format(Messages.FeedbackUserBanned, toBan.Mention,
Utils.GetHumanizedTimeOffset(duration), Utils.Wrap(reason)); Utils.GetHumanizedTimeOffset(duration), Utils.Wrap(reason));
cmd.Reply(feedback, ReplyEmojis.Banned); cmd.Reply(feedback, ReplyEmojis.Banned);
cmd.Audit(feedback); cmd.Audit(feedback);
GuildData.FromSocketGuild(guild).MemberData[toBan.Id].BannedUntil
= DateTimeOffset.Now.Add(duration).ToUnixTimeSeconds();
} }
} }

View file

@ -1,3 +1,4 @@
using Boyfriend.Data;
using Discord; using Discord;
using Discord.WebSocket; using Discord.WebSocket;
@ -22,6 +23,8 @@ public sealed class KickCommand : ICommand {
string.Format(Messages.YouWereKicked, cmd.Context.User.Mention, cmd.Context.Guild.Name, string.Format(Messages.YouWereKicked, cmd.Context.User.Mention, cmd.Context.Guild.Name,
Utils.Wrap(reason))); Utils.Wrap(reason)));
GuildData.FromSocketGuild(cmd.Context.Guild).MemberData[toKick.Id].Roles.Clear();
await toKick.KickAsync(guildKickMessage); await toKick.KickAsync(guildKickMessage);
var format = string.Format(Messages.FeedbackMemberKicked, toKick.Mention, Utils.Wrap(reason)); var format = string.Format(Messages.FeedbackMemberKicked, toKick.Mention, Utils.Wrap(reason));
cmd.Reply(format, ReplyEmojis.Kicked); cmd.Reply(format, ReplyEmojis.Kicked);

View file

@ -36,7 +36,8 @@ public sealed class MuteCommand : ICommand {
var hasDuration = duration.TotalSeconds > 0; var hasDuration = duration.TotalSeconds > 0;
if (role is not null) { if (role is not null) {
if (data.Preferences["RemoveRolesOnMute"] is "true") await toMute.RemoveRolesAsync(toMute.Roles); if (data.Preferences["RemoveRolesOnMute"] is "true")
await toMute.RemoveRolesAsync(toMute.Roles, requestOptions);
await toMute.AddRoleAsync(role, requestOptions); await toMute.AddRoleAsync(role, requestOptions);

View file

@ -0,0 +1,19 @@
using Boyfriend.Data;
namespace Boyfriend.Commands;
public sealed class RemindCommand : ICommand {
public string[] Aliases { get; } = { "remind", "reminder", "remindme", "напомни", "напомнить", "напоминание" };
public Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) {
var remindIn = CommandProcessor.GetTimeSpan(args, 0);
var reminderText = cmd.GetRemaining(args, 1, "ReminderText");
if (reminderText is not null)
GuildData.FromSocketGuild(cmd.Context.Guild).MemberData[cmd.Context.User.Id].Reminders.Add(new Reminder {
RemindAt = DateTimeOffset.Now.Add(remindIn).ToUnixTimeSeconds(),
ReminderText = reminderText
});
return Task.CompletedTask;
}
}

View file

@ -16,7 +16,7 @@ public sealed class SettingsCommand : ICommand {
if (args.Length is 0) { if (args.Length is 0) {
var currentSettings = Boyfriend.StringBuilder.AppendLine(Messages.CurrentSettings); var currentSettings = Boyfriend.StringBuilder.AppendLine(Messages.CurrentSettings);
foreach (var setting in GuildData.DefaultConfiguration) { foreach (var setting in GuildData.DefaultPreferences) {
var format = "{0}"; var format = "{0}";
var currentValue = config[setting.Key] is "default" var currentValue = config[setting.Key] is "default"
? Messages.DefaultWelcomeMessage ? Messages.DefaultWelcomeMessage
@ -47,7 +47,7 @@ public sealed class SettingsCommand : ICommand {
var exists = false; var exists = false;
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
// Too many allocations // Too many allocations
foreach (var setting in GuildData.DefaultConfiguration.Keys) { foreach (var setting in GuildData.DefaultPreferences.Keys) {
if (selectedSetting != setting.ToLower()) continue; if (selectedSetting != setting.ToLower()) continue;
selectedSetting = setting; selectedSetting = setting;
exists = true; exists = true;
@ -74,7 +74,7 @@ public sealed class SettingsCommand : ICommand {
} }
} else { value = "reset"; } } else { value = "reset"; }
if (IsBool(GuildData.DefaultConfiguration[selectedSetting]) && !IsBool(value)) { if (IsBool(GuildData.DefaultPreferences[selectedSetting]) && !IsBool(value)) {
value = value switch { value = value switch {
"y" or "yes" or "д" or "да" => "true", "y" or "yes" or "д" or "да" => "true",
"n" or "no" or "н" or "нет" => "false", "n" or "no" or "н" or "нет" => "false",
@ -99,14 +99,14 @@ public sealed class SettingsCommand : ICommand {
var formattedValue = selectedSetting switch { var formattedValue = selectedSetting switch {
"WelcomeMessage" => Utils.Wrap(Messages.DefaultWelcomeMessage), "WelcomeMessage" => Utils.Wrap(Messages.DefaultWelcomeMessage),
"EventStartedReceivers" => Utils.Wrap(GuildData.DefaultConfiguration[selectedSetting])!, "EventStartedReceivers" => Utils.Wrap(GuildData.DefaultPreferences[selectedSetting])!,
_ => value is "reset" or "default" ? Messages.SettingNotDefined _ => value is "reset" or "default" ? Messages.SettingNotDefined
: IsBool(value) ? YesOrNo(value is "true") : IsBool(value) ? YesOrNo(value is "true")
: string.Format(formatting, value) : string.Format(formatting, value)
}; };
if (value is "reset" or "default") { if (value is "reset" or "default") {
config[selectedSetting] = GuildData.DefaultConfiguration[selectedSetting]; config[selectedSetting] = GuildData.DefaultPreferences[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),
@ -139,7 +139,7 @@ public sealed class SettingsCommand : ICommand {
} }
if (selectedSetting is "Lang") { if (selectedSetting is "Lang") {
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild);
localizedSelectedSetting = Utils.GetMessage($"Settings{selectedSetting}"); localizedSelectedSetting = Utils.GetMessage($"Settings{selectedSetting}");
} }

View file

@ -20,10 +20,12 @@ public sealed class UnmuteCommand : ICommand {
public static async Task UnmuteMemberAsync(CommandProcessor cmd, SocketGuildUser toUnmute, public static async Task UnmuteMemberAsync(CommandProcessor cmd, SocketGuildUser toUnmute,
string reason) { string reason) {
var requestOptions = Utils.GetRequestOptions($"({cmd.Context.User}) {reason}"); var requestOptions = Utils.GetRequestOptions($"({cmd.Context.User}) {reason}");
var role = GuildData.FromSocketGuild(cmd.Context.Guild).MuteRole; var data = GuildData.FromSocketGuild(cmd.Context.Guild);
var role = data.MuteRole;
if (role is not null && toUnmute.Roles.Contains(role)) { if (role is not null && toUnmute.Roles.Contains(role)) {
// TODO: Return roles await toUnmute.AddRolesAsync(data.MemberData[toUnmute.Id].Roles, requestOptions);
await toUnmute.RemoveRoleAsync(role, requestOptions);
} else { } else {
if (toUnmute.TimedOutUntil is null || toUnmute.TimedOutUntil.Value.ToUnixTimeSeconds() < if (toUnmute.TimedOutUntil is null || toUnmute.TimedOutUntil.Value.ToUnixTimeSeconds() <
DateTimeOffset.Now.ToUnixTimeSeconds()) { DateTimeOffset.Now.ToUnixTimeSeconds()) {
@ -31,7 +33,7 @@ public sealed class UnmuteCommand : ICommand {
return; return;
} }
await toUnmute.RemoveTimeOutAsync(); await toUnmute.RemoveTimeOutAsync(requestOptions);
} }
var feedback = string.Format(Messages.FeedbackMemberUnmuted, toUnmute.Mention, Utils.Wrap(reason)); var feedback = string.Format(Messages.FeedbackMemberUnmuted, toUnmute.Mention, Utils.Wrap(reason));

View file

@ -5,7 +5,7 @@ using Discord.WebSocket;
namespace Boyfriend.Data; namespace Boyfriend.Data;
public record GuildData { public record GuildData {
public static readonly Dictionary<string, string> DefaultConfiguration = new() { public static readonly Dictionary<string, string> DefaultPreferences = new() {
{ "Prefix", "!" }, { "Prefix", "!" },
{ "Lang", "en" }, { "Lang", "en" },
{ "ReceiveStartupMessages", "false" }, { "ReceiveStartupMessages", "false" },
@ -21,6 +21,7 @@ public record GuildData {
{ "EventNotificationRole", "0" }, { "EventNotificationRole", "0" },
{ "EventNotificationChannel", "0" }, { "EventNotificationChannel", "0" },
{ "EventEarlyNotificationOffset", "0" } { "EventEarlyNotificationOffset", "0" }
// TODO: { "AutoStartEvents", "false" }
}; };
private static readonly Dictionary<ulong, GuildData> GuildDataDictionary = new(); private static readonly Dictionary<ulong, GuildData> GuildDataDictionary = new();
@ -36,52 +37,49 @@ public record GuildData {
[SuppressMessage("Performance", "CA1853:Unnecessary call to \'Dictionary.ContainsKey(key)\'")] [SuppressMessage("Performance", "CA1853:Unnecessary call to \'Dictionary.ContainsKey(key)\'")]
// https://github.com/dotnet/roslyn-analyzers/issues/6377 // https://github.com/dotnet/roslyn-analyzers/issues/6377
private GuildData(SocketGuild guild) { private GuildData(SocketGuild guild) {
var id = guild.Id; if (!Directory.Exists($"{_id}")) Directory.CreateDirectory($"{_id}");
if (!Directory.Exists($"{id}")) Directory.CreateDirectory($"{id}"); if (!Directory.Exists($"{_id}/MemberData")) Directory.CreateDirectory($"{_id}/MemberData");
if (!Directory.Exists($"{id}/MemberData")) Directory.CreateDirectory($"{id}/MemberData"); if (!File.Exists($"{_id}/Configuration.json")) File.Create($"{_id}/Configuration.json").Dispose();
if (!File.Exists($"{id}/Configuration.json")) File.Create($"{id}/Configuration.json").Dispose();
Preferences Preferences
= JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText($"{id}/Configuration.json")) ?? = JsonSerializer.Deserialize<Dictionary<string, string>>(File.ReadAllText($"{_id}/Configuration.json")) ??
new Dictionary<string, string>(); new Dictionary<string, string>();
// ReSharper disable twice ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator // ReSharper disable twice ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
if (Preferences.Keys.Count < DefaultConfiguration.Keys.Count) if (Preferences.Keys.Count < DefaultPreferences.Keys.Count)
foreach (var key in DefaultConfiguration.Keys) foreach (var key in DefaultPreferences.Keys)
if (!Preferences.ContainsKey(key)) if (!Preferences.ContainsKey(key))
Preferences.Add(key, DefaultConfiguration[key]); Preferences.Add(key, DefaultPreferences[key]);
if (Preferences.Keys.Count > DefaultConfiguration.Keys.Count) if (Preferences.Keys.Count > DefaultPreferences.Keys.Count)
foreach (var key in Preferences.Keys) foreach (var key in Preferences.Keys)
if (!DefaultConfiguration.ContainsKey(key)) if (!DefaultPreferences.ContainsKey(key))
Preferences.Remove(key); Preferences.Remove(key);
Preferences.TrimExcess(); Preferences.TrimExcess();
MemberData = new Dictionary<ulong, MemberData>(); MemberData = new Dictionary<ulong, MemberData>();
foreach (var data in Directory.GetFiles($"{id}/MemberData")) { foreach (var data in Directory.GetFiles($"{_id}/MemberData")) {
var deserialised = JsonSerializer.Deserialize<MemberData>(File.ReadAllText($"{id}/MemberData/{data}.json")); var deserialised
= JsonSerializer.Deserialize<MemberData>(File.ReadAllText($"{_id}/MemberData/{data}.json"));
MemberData.Add(deserialised!.Id, deserialised); MemberData.Add(deserialised!.Id, deserialised);
} }
if (guild.MemberCount > MemberData.Count)
foreach (var member in guild.Users) { foreach (var member in guild.Users) {
if (MemberData.TryGetValue(member.Id, out var memberData)) { if (MemberData.TryGetValue(member.Id, out var memberData)) {
if (!memberData.IsInGuild && if (!memberData.IsInGuild &&
DateTimeOffset.Now.ToUnixTimeSeconds() - DateTimeOffset.Now.ToUnixTimeSeconds() -
Math.Max(memberData.LeftAt.Last(), memberData.BannedUntil) > Math.Max(memberData.LeftAt.Last(), memberData.BannedUntil) >
60 * 60 * 24 * 30) { 60 * 60 * 24 * 30) {
File.Delete($"{id}/MemberData/{memberData.Id}.json"); File.Delete($"{_id}/MemberData/{memberData.Id}.json");
MemberData.Remove(memberData.Id); MemberData.Remove(memberData.Id);
} }
continue; continue;
} }
var data = new MemberData(member); MemberData.Add(member.Id, new MemberData(member));
MemberData.Add(member.Id, data);
File.WriteAllText($"{id}/MemberData/{data.Id}.json",
JsonSerializer.Serialize(data));
} }
GuildDataDictionary.Add(id, this); MemberData.TrimExcess();
} }
public SocketRole? MuteRole { public SocketRole? MuteRole {
@ -98,4 +96,14 @@ public record GuildData {
GuildDataDictionary.Add(guild.Id, newData); GuildDataDictionary.Add(guild.Id, newData);
return newData; return newData;
} }
public async Task Save(bool saveMemberData) {
Preferences.TrimExcess();
await File.WriteAllTextAsync($"{_id}/Configuration.json",
JsonSerializer.Serialize(Preferences));
if (saveMemberData)
foreach (var data in MemberData.Values)
await File.WriteAllTextAsync($"{_id}/MemberData/{data.Id}.json",
JsonSerializer.Serialize(data));
}
} }

View file

@ -1,3 +1,5 @@
using System.Diagnostics;
using Boyfriend.Data;
using Discord; using Discord;
using Discord.Rest; using Discord.Rest;
using Discord.WebSocket; using Discord.WebSocket;
@ -26,9 +28,9 @@ public static class EventHandler {
var i = Random.Shared.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 = GuildData.FromSocketGuild(guild).Preferences;
var channel = guild.GetTextChannel(Utils.ParseMention(config["BotLogChannel"])); var channel = guild.GetTextChannel(Utils.ParseMention(config["BotLogChannel"]));
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild);
if (config["ReceiveStartupMessages"] is not "true" || channel is 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)));
@ -46,7 +48,7 @@ public static class EventHandler {
var guild = gChannel.Guild; var guild = gChannel.Guild;
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild);
var mention = msg.Author.Mention; var mention = msg.Author.Mention;
@ -58,7 +60,7 @@ public static class EventHandler {
await Utils.SendFeedbackAsync(string.Format(Messages.CachedMessageDeleted, msg.Author.Mention, await Utils.SendFeedbackAsync(string.Format(Messages.CachedMessageDeleted, msg.Author.Mention,
Utils.MentionChannel(channel.Id), Utils.MentionChannel(channel.Id),
Utils.Wrap(msg.CleanContent)), guild.Id, mention); Utils.Wrap(msg.CleanContent)), guild, mention);
} }
private static Task MessageReceivedEvent(IDeletable messageParam) { private static Task MessageReceivedEvent(IDeletable messageParam) {
@ -82,19 +84,20 @@ public static class EventHandler {
msg.CleanContent == messageSocket.CleanContent || msg.Author.IsBot) return; msg.CleanContent == messageSocket.CleanContent || msg.Author.IsBot) return;
var guild = gChannel.Guild; var guild = gChannel.Guild;
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild);
var isLimitedSpace = msg.CleanContent.Length + messageSocket.CleanContent.Length < 1940; var isLimitedSpace = msg.CleanContent.Length + messageSocket.CleanContent.Length < 1940;
await Utils.SendFeedbackAsync(string.Format(Messages.CachedMessageEdited, Utils.MentionChannel(channel.Id), await Utils.SendFeedbackAsync(string.Format(Messages.CachedMessageEdited, Utils.MentionChannel(channel.Id),
Utils.Wrap(msg.CleanContent, isLimitedSpace), Utils.Wrap(messageSocket.CleanContent, isLimitedSpace)), Utils.Wrap(msg.CleanContent, isLimitedSpace), Utils.Wrap(messageSocket.CleanContent, isLimitedSpace)),
guild.Id, msg.Author.Mention); guild, msg.Author.Mention);
} }
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 data = GuildData.FromSocketGuild(guild);
Utils.SetCurrentLanguage(guild.Id); var config = data.Preferences;
Utils.SetCurrentLanguage(guild);
if (config["SendWelcomeMessages"] is "true") if (config["SendWelcomeMessages"] is "true")
await Utils.SilentSendAsync(guild.SystemChannel, await Utils.SilentSendAsync(guild.SystemChannel,
@ -103,27 +106,42 @@ public static class EventHandler {
: config["WelcomeMessage"], user.Mention, guild.Name)); : 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"]));
if (!data.MemberData.ContainsKey(user.Id)) data.MemberData.Add(user.Id, new MemberData(user));
var memberData = data.MemberData[user.Id];
memberData.IsInGuild = true;
memberData.BannedUntil = 0;
if (memberData.LeftAt.Count > 0) {
if (memberData.JoinedAt.Contains(user.JoinedAt!.Value.ToUnixTimeSeconds()))
throw new UnreachableException();
memberData.JoinedAt.Add(user.JoinedAt!.Value.ToUnixTimeSeconds());
} }
private static async Task UserLeftEvent(SocketGuildUser user) { if (memberData.MutedUntil < DateTimeOffset.Now.ToUnixTimeSeconds()) {
var guild = user.Guild; if (data.MuteRole is not null)
var config = Boyfriend.GetGuildConfig(guild.Id); await user.AddRoleAsync(data.MuteRole);
Utils.SetCurrentLanguage(guild.Id); else
await user.SetTimeOutAsync(
TimeSpan.FromSeconds(DateTimeOffset.Now.ToUnixTimeSeconds() - memberData.MutedUntil));
if (config["SendWelcomeMessages"] is "true") if (config["RemoveRolesOnMute"] is "false" && config["ReturnRolesOnRejoin"] is "true")
await Utils.SilentSendAsync(guild.SystemChannel, await user.AddRolesAsync(memberData.Roles);
string.Format(config["WelcomeMessage"] is "default" } else if (config["ReturnRolesOnRejoin"] is "true") { await user.AddRolesAsync(memberData.Roles); }
? Messages.DefaultWelcomeMessage
: config["WelcomeMessage"], user.Mention, guild.Name));
if (config["StarterRole"] is not "0") await user.AddRoleAsync(ulong.Parse(config["StarterRole"]));
} }
private static Task UserLeftEvent(SocketGuild guild, SocketUser user) {
var data = GuildData.FromSocketGuild(guild).MemberData[user.Id];
data.IsInGuild = false;
data.LeftAt.Add(DateTimeOffset.Now.ToUnixTimeSeconds());
return Task.CompletedTask;
}
// TODO: store data about event (early) notifications
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 = GuildData.FromSocketGuild(guild).Preferences;
var channel = Utils.GetEventNotificationChannel(guild); var channel = Utils.GetEventNotificationChannel(guild);
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild);
if (channel is not null) { if (channel is not null) {
var role = guild.GetRole(ulong.Parse(eventConfig["EventNotificationRole"])); var role = guild.GetRole(ulong.Parse(eventConfig["EventNotificationRole"]));
@ -141,17 +159,13 @@ public static class EventHandler {
scheduledEvent.StartTime.ToUnixTimeSeconds().ToString(), descAndLink), scheduledEvent.StartTime.ToUnixTimeSeconds().ToString(), descAndLink),
true); true);
} }
if (eventConfig["EventEarlyNotificationOffset"] is not "0")
_ = Utils.SendEarlyEventStartNotificationAsync(channel, scheduledEvent,
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 = GuildData.FromSocketGuild(guild).Preferences;
var channel = Utils.GetEventNotificationChannel(guild); var channel = Utils.GetEventNotificationChannel(guild);
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild);
if (channel is not 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}" : ""));
@ -159,9 +173,9 @@ 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 = GuildData.FromSocketGuild(guild).Preferences;
var channel = Utils.GetEventNotificationChannel(guild); var channel = Utils.GetEventNotificationChannel(guild);
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild);
if (channel is not null) { if (channel is not null) {
var receivers = eventConfig["EventStartedReceivers"]; var receivers = eventConfig["EventStartedReceivers"];
@ -183,7 +197,7 @@ 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 channel = Utils.GetEventNotificationChannel(guild); var channel = Utils.GetEventNotificationChannel(guild);
Utils.SetCurrentLanguage(guild.Id); Utils.SetCurrentLanguage(guild);
if (channel is not null) if (channel is not null)
await channel.SendMessageAsync(string.Format(Messages.EventCompleted, Utils.Wrap(scheduledEvent.Name), await channel.SendMessageAsync(string.Format(Messages.EventCompleted, Utils.Wrap(scheduledEvent.Name),
Utils.GetHumanizedTimeOffset(DateTimeOffset.Now.Subtract(scheduledEvent.StartTime)))); Utils.GetHumanizedTimeOffset(DateTimeOffset.Now.Subtract(scheduledEvent.StartTime))));

View file

@ -3,6 +3,7 @@ using System.Globalization;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Boyfriend.Data;
using Discord; using Discord;
using Discord.Net; using Discord.Net;
using Discord.WebSocket; using Discord.WebSocket;
@ -28,9 +29,8 @@ public static partial class Utils {
return GetMessage($"Beep{(i < 0 ? Random.Shared.Next(3) + 1 : ++i)}"); return GetMessage($"Beep{(i < 0 ? Random.Shared.Next(3) + 1 : ++i)}");
} }
public static SocketTextChannel? GetBotLogChannel(ulong id) { public static SocketTextChannel? GetBotLogChannel(SocketGuild guild) {
return Boyfriend.Client.GetGuild(id) return guild.GetTextChannel(ParseMention(GuildData.FromSocketGuild(guild).Preferences["BotLogChannel"]));
.GetTextChannel(ParseMention(Boyfriend.GetGuildConfig(id)["BotLogChannel"]));
} }
public static string? Wrap(string? original, bool limitedSpace = false) { public static string? Wrap(string? original, bool limitedSpace = false) {
@ -91,22 +91,22 @@ public static partial class Utils {
} }
public static async Task public static async Task
SendFeedbackAsync(string feedback, ulong guildId, string mention, bool sendPublic = false) { SendFeedbackAsync(string feedback, SocketGuild guild, string mention, bool sendPublic = false) {
var adminChannel = GetBotLogChannel(guildId); var adminChannel = GetBotLogChannel(guild);
var systemChannel = Boyfriend.Client.GetGuild(guildId).SystemChannel; var systemChannel = guild.SystemChannel;
var toSend = $"*[{mention}: {feedback}]*"; var toSend = $"*[{mention}: {feedback}]*";
if (adminChannel is not null) await SilentSendAsync(adminChannel, toSend); if (adminChannel is not null) await SilentSendAsync(adminChannel, toSend);
if (sendPublic && systemChannel is not 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) {
return span.TotalSeconds > 0 return span.TotalSeconds < 1
? $" {span.Humanize(2, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Month, culture: Messages.Culture.Name.Contains("RU") ? CultureInfoCache["ru"] : Messages.Culture)}" ? Messages.Ever
: Messages.Ever; : $" {span.Humanize(2, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Month, culture: Messages.Culture.Name.Contains("RU") ? CultureInfoCache["ru"] : Messages.Culture)}";
} }
public static void SetCurrentLanguage(ulong guildId) { public static void SetCurrentLanguage(SocketGuild guild) {
Messages.Culture = CultureInfoCache[Boyfriend.GetGuildConfig(guildId)["Lang"]]; Messages.Culture = CultureInfoCache[GuildData.FromSocketGuild(guild).Preferences["Lang"]];
} }
public static void SafeAppendToBuilder(StringBuilder appendTo, string appendWhat, SocketTextChannel? channel) { public static void SafeAppendToBuilder(StringBuilder appendTo, string appendWhat, SocketTextChannel? channel) {
@ -129,7 +129,8 @@ public static partial class Utils {
} }
public static SocketTextChannel? GetEventNotificationChannel(SocketGuild guild) { public static SocketTextChannel? GetEventNotificationChannel(SocketGuild guild) {
return guild.GetTextChannel(ParseMention(Boyfriend.GetGuildConfig(guild.Id)["EventNotificationChannel"])); return guild.GetTextChannel(ParseMention(GuildData.FromSocketGuild(guild)
.Preferences["EventNotificationChannel"]));
} }
[GeneratedRegex("[^0-9]")] [GeneratedRegex("[^0-9]")]