From 1f45a605d79362a5171ed0bdd06f2b52ab95e751 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Mon, 16 Jan 2023 20:33:02 +0500 Subject: [PATCH] Finish adapting code to new guild data storage --- Boyfriend/Boyfriend.cs | 97 ++++++++++++++++++++++----- Boyfriend/CommandProcessor.cs | 12 ++-- Boyfriend/Commands/BanCommand.cs | 2 +- Boyfriend/Commands/HelpCommand.cs | 2 +- Boyfriend/Commands/KickCommand.cs | 2 +- Boyfriend/Commands/MuteCommand.cs | 2 +- Boyfriend/Commands/RemindCommand.cs | 7 +- Boyfriend/Commands/SettingsCommand.cs | 12 ++-- Boyfriend/Commands/UnmuteCommand.cs | 20 ++---- Boyfriend/Data/GuildData.cs | 45 ++++++++++--- Boyfriend/Data/Reminder.cs | 1 + Boyfriend/EventHandler.cs | 22 +++--- Boyfriend/Messages.Designer.cs | 18 ++--- Boyfriend/Messages.resx | 8 +-- Boyfriend/Messages.ru.resx | 8 +-- Boyfriend/Messages.tt-ru.resx | 8 +-- Boyfriend/Utils.cs | 31 ++++++--- 17 files changed, 201 insertions(+), 96 deletions(-) diff --git a/Boyfriend/Boyfriend.cs b/Boyfriend/Boyfriend.cs index c82a295..8d3e07c 100644 --- a/Boyfriend/Boyfriend.cs +++ b/Boyfriend/Boyfriend.cs @@ -1,6 +1,10 @@ using System.Text; +using System.Timers; +using Boyfriend.Data; using Discord; +using Discord.Rest; using Discord.WebSocket; +using Timer = System.Timers.Timer; namespace Boyfriend; @@ -18,7 +22,10 @@ public static class Boyfriend { LargeThreshold = 500 }; - private static readonly List> ActivityList = new() { + private static DateTimeOffset _nextSongAt = DateTimeOffset.MinValue; + private static uint _nextSongIndex; + + private static readonly Tuple[] ActivityList = { Tuple.Create(new Game("Masayoshi Minoshima (ft. nomico) - Bad Apple!!", ActivityType.Listening), new TimeSpan(0, 3, 40)), Tuple.Create(new Game("Xi - Blue Zenith", ActivityType.Listening), new TimeSpan(0, 4, 16)), @@ -30,11 +37,13 @@ public static class Boyfriend { public static readonly DiscordSocketClient Client = new(Config); + private static readonly List GuildTickTasks = new(); + public static void Main() { - Init().GetAwaiter().GetResult(); + InitAsync().GetAwaiter().GetResult(); } - private static async Task Init() { + private static async Task InitAsync() { var token = (await File.ReadAllTextAsync("token.txt")).Trim(); Client.Log += Log; @@ -44,13 +53,34 @@ public static class Boyfriend { EventHandler.InitEvents(); - while (ActivityList.Count > 0) - foreach (var activity in ActivityList) { - await Client.SetActivityAsync(activity.Item1); - await Task.Delay(activity.Item2); + var timer = new Timer(); + timer.Interval = 1000; + timer.AutoReset = true; + timer.Elapsed += TickAllGuildsAsync; + timer.Start(); + + while (ActivityList.Length > 0) + if (DateTimeOffset.Now >= _nextSongAt) { + var nextSong = ActivityList[_nextSongIndex]; + await Client.SetActivityAsync(nextSong.Item1); + _nextSongAt = DateTimeOffset.Now.Add(nextSong.Item2); + _nextSongIndex++; + if (_nextSongIndex >= ActivityList.Length) _nextSongIndex = 0; } } + private static async void TickAllGuildsAsync(object? sender, ElapsedEventArgs e) { + foreach (var guild in Client.Guilds) GuildTickTasks.Add(TickGuildAsync(guild)); + + try { Task.WaitAll(GuildTickTasks.ToArray()); } catch (AggregateException ex) { + foreach (var exc in ex.InnerExceptions) + await Log(new LogMessage(LogSeverity.Error, nameof(CommandProcessor), + "Exception while executing commands", exc)); + } + + GuildTickTasks.Clear(); + } + public static Task Log(LogMessage msg) { switch (msg.Severity) { case LogSeverity.Critical: @@ -78,18 +108,51 @@ public static class Boyfriend { return Task.CompletedTask; } - /*public static Dictionary> GetRemovedRoles(ulong id) { - if (RemovedRolesDictionary.TryGetValue(id, out var dict)) return dict; - var path = $"removedroles_{id}.json"; + private static async Task TickGuildAsync(SocketGuild guild) { + var data = GuildData.Get(guild); + var config = data.Preferences; + _ = int.TryParse(config["EventEarlyNotificationOffset"], out var offset); + foreach (var schEvent in guild.Events) + if (config["AutoStartEvents"] is "true" && DateTimeOffset.Now >= schEvent.StartTime) { + await schEvent.StartAsync(); + } else if (!data.EarlyNotifications.Contains(schEvent.Id) && + DateTimeOffset.Now >= schEvent.StartTime.Subtract(new TimeSpan(0, offset, 0))) { + var receivers = config["EventStartedReceivers"]; + var role = guild.GetRole(ulong.Parse(config["EventNotificationRole"])); + var mentions = StringBuilder; - if (!File.Exists(path)) File.Create(path).Dispose(); + if (receivers.Contains("role") && role is not null) mentions.Append($"{role.Mention} "); + if (receivers.Contains("users") || receivers.Contains("interested")) + mentions = (await schEvent.GetUsersAsync(15)) + .Where(user => role is null || !((RestGuildUser)user).RoleIds.Contains(role.Id)) + .Aggregate(mentions, (current, user) => current.Append($"{user.Mention} ")); - var json = File.ReadAllText(path); - var removedRoles = JsonConvert.DeserializeObject>>(json) - ?? new Dictionary>(); + await Utils.GetEventNotificationChannel(guild)?.SendMessageAsync(string.Format(Messages.EventStarted, + mentions, + Utils.Wrap(schEvent.Name), + Utils.Wrap(schEvent.Location) ?? Utils.MentionChannel(schEvent.Channel.Id)))!; + mentions.Clear(); + data.EarlyNotifications.Add(schEvent.Id); + } - RemovedRolesDictionary.Add(id, removedRoles); + foreach (var mData in data.MemberData.Values) { + if (DateTimeOffset.Now >= mData.BannedUntil) _ = guild.RemoveBanAsync(mData.Id); - return removedRoles; - }*/ + if (mData.IsInGuild) { + if (DateTimeOffset.Now >= mData.MutedUntil) + await Utils.UnmuteMemberAsync(data, Client.CurrentUser.ToString(), guild.GetUser(mData.Id), + Messages.PunishmentExpired); + + foreach (var reminder in mData.Reminders) { + var channel = guild.GetTextChannel(reminder.ReminderChannel); + if (channel is null) { + await Utils.SendDirectMessage(Client.GetUser(mData.Id), reminder.ReminderText); + continue; + } + + await channel.SendMessageAsync($"<@{mData.Id}> {Utils.Wrap(reminder.ReminderText)}"); + } + } + } + } } diff --git a/Boyfriend/CommandProcessor.cs b/Boyfriend/CommandProcessor.cs index 62677c2..698e908 100644 --- a/Boyfriend/CommandProcessor.cs +++ b/Boyfriend/CommandProcessor.cs @@ -32,7 +32,7 @@ public sealed class CommandProcessor { public async Task HandleCommandAsync() { var guild = Context.Guild; - var data = GuildData.FromSocketGuild(guild); + var data = GuildData.Get(guild); Utils.SetCurrentLanguage(guild); if (GetMember().Roles.Contains(data.MuteRole)) { @@ -80,8 +80,9 @@ public sealed class CommandProcessor { public void Audit(string action, bool isPublic = true) { var format = $"*[{Context.User.Mention}: {action}]*"; - if (isPublic) Utils.SafeAppendToBuilder(_stackedPublicFeedback, format, Context.Guild.SystemChannel); - Utils.SafeAppendToBuilder(_stackedPrivateFeedback, format, Utils.GetBotLogChannel(Context.Guild)); + var data = GuildData.Get(Context.Guild); + if (isPublic) Utils.SafeAppendToBuilder(_stackedPublicFeedback, format, data.PublicFeedbackChannel); + Utils.SafeAppendToBuilder(_stackedPrivateFeedback, format, data.PrivateFeedbackChannel); if (_tasks.Count is 0) SendFeedbacks(false); } @@ -89,8 +90,9 @@ public sealed class CommandProcessor { if (reply && _stackedReplyMessage.Length > 0) _ = Context.Message.ReplyAsync(_stackedReplyMessage.ToString(), false, null, AllowedMentions.None); - var adminChannel = Utils.GetBotLogChannel(Context.Guild); - var systemChannel = Context.Guild.SystemChannel; + var data = GuildData.Get(Context.Guild); + var adminChannel = data.PublicFeedbackChannel; + var systemChannel = data.PrivateFeedbackChannel; if (_stackedPrivateFeedback.Length > 0 && adminChannel is not null && adminChannel.Id != Context.Message.Channel.Id) { _ = Utils.SilentSendAsync(adminChannel, _stackedPrivateFeedback.ToString()); diff --git a/Boyfriend/Commands/BanCommand.cs b/Boyfriend/Commands/BanCommand.cs index 3297156..e5ab6e2 100644 --- a/Boyfriend/Commands/BanCommand.cs +++ b/Boyfriend/Commands/BanCommand.cs @@ -30,7 +30,7 @@ public sealed class BanCommand : ICommand { var guildBanMessage = $"({author}) {reason}"; await guild.AddBanAsync(toBan.Item1, 0, guildBanMessage); - var memberData = GuildData.FromSocketGuild(guild).MemberData[toBan.Item1]; + var memberData = GuildData.Get(guild).MemberData[toBan.Item1]; memberData.BannedUntil = duration.TotalSeconds < 1 ? DateTimeOffset.MaxValue : DateTimeOffset.Now.Add(duration); memberData.Roles.Clear(); diff --git a/Boyfriend/Commands/HelpCommand.cs b/Boyfriend/Commands/HelpCommand.cs index 99df178..72b788b 100644 --- a/Boyfriend/Commands/HelpCommand.cs +++ b/Boyfriend/Commands/HelpCommand.cs @@ -7,7 +7,7 @@ public sealed class HelpCommand : ICommand { public string[] Aliases { get; } = { "help", "помощь", "справка" }; public Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) { - var prefix = GuildData.FromSocketGuild(cmd.Context.Guild).Preferences["Prefix"]; + var prefix = GuildData.Get(cmd.Context.Guild).Preferences["Prefix"]; var toSend = Boyfriend.StringBuilder.Append(Messages.CommandHelp); foreach (var command in CommandProcessor.Commands) diff --git a/Boyfriend/Commands/KickCommand.cs b/Boyfriend/Commands/KickCommand.cs index 6c8f0f2..fb09449 100644 --- a/Boyfriend/Commands/KickCommand.cs +++ b/Boyfriend/Commands/KickCommand.cs @@ -23,7 +23,7 @@ public sealed class KickCommand : ICommand { string.Format(Messages.YouWereKicked, cmd.Context.User.Mention, cmd.Context.Guild.Name, Utils.Wrap(reason))); - GuildData.FromSocketGuild(cmd.Context.Guild).MemberData[toKick.Id].Roles.Clear(); + GuildData.Get(cmd.Context.Guild).MemberData[toKick.Id].Roles.Clear(); await toKick.KickAsync(guildKickMessage); var format = string.Format(Messages.FeedbackMemberKicked, toKick.Mention, Utils.Wrap(reason)); diff --git a/Boyfriend/Commands/MuteCommand.cs b/Boyfriend/Commands/MuteCommand.cs index db201aa..c704212 100644 --- a/Boyfriend/Commands/MuteCommand.cs +++ b/Boyfriend/Commands/MuteCommand.cs @@ -14,7 +14,7 @@ public sealed class MuteCommand : ICommand { var duration = CommandProcessor.GetTimeSpan(args, 1); var reason = cmd.GetRemaining(args, duration.TotalSeconds < 1 ? 1 : 2, "MuteReason"); if (reason is null) return; - var guildData = GuildData.FromSocketGuild(cmd.Context.Guild); + var guildData = GuildData.Get(cmd.Context.Guild); var role = guildData.MuteRole; if ((role is not null && toMute.Roles.Contains(role)) diff --git a/Boyfriend/Commands/RemindCommand.cs b/Boyfriend/Commands/RemindCommand.cs index 0147f28..8802a2c 100644 --- a/Boyfriend/Commands/RemindCommand.cs +++ b/Boyfriend/Commands/RemindCommand.cs @@ -7,11 +7,12 @@ public sealed class RemindCommand : ICommand { public Task RunAsync(CommandProcessor cmd, string[] args, string[] cleanArgs) { var remindIn = CommandProcessor.GetTimeSpan(args, 0); - var reminderText = cmd.GetRemaining(args, 1, "ReminderText"); + var reminderText = cmd.GetRemaining(cleanArgs, 1, "ReminderText"); if (reminderText is not null) - GuildData.FromSocketGuild(cmd.Context.Guild).MemberData[cmd.Context.User.Id].Reminders.Add(new Reminder { + GuildData.Get(cmd.Context.Guild).MemberData[cmd.Context.User.Id].Reminders.Add(new Reminder { RemindAt = DateTimeOffset.Now.Add(remindIn), - ReminderText = reminderText + ReminderText = reminderText, + ReminderChannel = cmd.Context.Channel.Id }); return Task.CompletedTask; diff --git a/Boyfriend/Commands/SettingsCommand.cs b/Boyfriend/Commands/SettingsCommand.cs index 3740a5d..ed5392a 100644 --- a/Boyfriend/Commands/SettingsCommand.cs +++ b/Boyfriend/Commands/SettingsCommand.cs @@ -10,7 +10,7 @@ public sealed class SettingsCommand : ICommand { if (!cmd.HasPermission(GuildPermission.ManageGuild)) return Task.CompletedTask; var guild = cmd.Context.Guild; - var data = GuildData.FromSocketGuild(guild); + var data = GuildData.Get(guild); var config = data.Preferences; if (args.Length is 0) { @@ -45,10 +45,7 @@ public sealed class SettingsCommand : ICommand { var selectedSetting = args[0].ToLower(); var exists = false; - // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator - // Too many allocations - foreach (var setting in GuildData.DefaultPreferences.Keys) { - if (selectedSetting != setting.ToLower()) continue; + foreach (var setting in GuildData.DefaultPreferences.Keys.Where(x => x.ToLower() == selectedSetting)) { selectedSetting = setting; exists = true; break; @@ -133,6 +130,11 @@ public sealed class SettingsCommand : ICommand { return Task.CompletedTask; } + if (selectedSetting.EndsWith("Offset") && !int.TryParse(value, out _)) { + cmd.Reply(Messages.InvalidSettingValue, ReplyEmojis.Error); + return Task.CompletedTask; + } + if (selectedSetting is "MuteRole") data.MuteRole = guild.GetRole(mention); config[selectedSetting] = value; diff --git a/Boyfriend/Commands/UnmuteCommand.cs b/Boyfriend/Commands/UnmuteCommand.cs index b25acc8..7a42460 100644 --- a/Boyfriend/Commands/UnmuteCommand.cs +++ b/Boyfriend/Commands/UnmuteCommand.cs @@ -17,22 +17,14 @@ public sealed class UnmuteCommand : ICommand { await UnmuteMemberAsync(cmd, toUnmute, reason); } - public static async Task UnmuteMemberAsync(CommandProcessor cmd, SocketGuildUser toUnmute, + private static async Task UnmuteMemberAsync(CommandProcessor cmd, SocketGuildUser toUnmute, string reason) { - var requestOptions = Utils.GetRequestOptions($"({cmd.Context.User}) {reason}"); - var data = GuildData.FromSocketGuild(cmd.Context.Guild); - var role = data.MuteRole; + var isMuted = await Utils.UnmuteMemberAsync(GuildData.Get(cmd.Context.Guild), cmd.Context.User.ToString(), + toUnmute, reason); - if (role is not null && toUnmute.Roles.Contains(role)) { - await toUnmute.AddRolesAsync(data.MemberData[toUnmute.Id].Roles, requestOptions); - await toUnmute.RemoveRoleAsync(role, requestOptions); - } else { - if (toUnmute.TimedOutUntil is null || toUnmute.TimedOutUntil.Value < DateTimeOffset.Now) { - cmd.Reply(Messages.MemberNotMuted, ReplyEmojis.Error); - return; - } - - await toUnmute.RemoveTimeOutAsync(requestOptions); + if (!isMuted) { + cmd.Reply(Messages.MemberNotMuted, ReplyEmojis.Error); + return; } var feedback = string.Format(Messages.FeedbackMemberUnmuted, toUnmute.Mention, Utils.Wrap(reason)); diff --git a/Boyfriend/Data/GuildData.cs b/Boyfriend/Data/GuildData.cs index b4b4db8..d8b5325 100644 --- a/Boyfriend/Data/GuildData.cs +++ b/Boyfriend/Data/GuildData.cs @@ -20,28 +20,37 @@ public record GuildData { { "EventStartedReceivers", "interested,role" }, { "EventNotificationRole", "0" }, { "EventNotificationChannel", "0" }, - { "EventEarlyNotificationOffset", "0" } - // TODO: { "AutoStartEvents", "false" } + { "EventEarlyNotificationOffset", "0" }, + { "AutoStartEvents", "false" } }; public static readonly Dictionary GuildDataDictionary = new(); + private readonly string _configurationFile; + + public readonly List EarlyNotifications = new(); + public readonly Dictionary MemberData; public readonly Dictionary Preferences; private SocketRole? _cachedMuteRole; + private SocketTextChannel? _cachedPrivateFeedbackChannel; + private SocketTextChannel? _cachedPublicFeedbackChannel; private ulong _id; [SuppressMessage("Performance", "CA1853:Unnecessary call to \'Dictionary.ContainsKey(key)\'")] // https://github.com/dotnet/roslyn-analyzers/issues/6377 private GuildData(SocketGuild guild) { - if (!Directory.Exists($"{_id}")) Directory.CreateDirectory($"{_id}"); - if (!Directory.Exists($"{_id}/MemberData")) Directory.CreateDirectory($"{_id}/MemberData"); - if (!File.Exists($"{_id}/Configuration.json")) File.Create($"{_id}/Configuration.json").Dispose(); + var idString = $"{_id}"; + var memberDataDir = $"{_id}/MemberData"; + _configurationFile = $"{_id}/Configuration.json"; + if (!Directory.Exists(idString)) Directory.CreateDirectory(idString); + if (!Directory.Exists(memberDataDir)) Directory.CreateDirectory(memberDataDir); + if (!File.Exists(_configurationFile)) File.Create(_configurationFile).Dispose(); Preferences - = JsonSerializer.Deserialize>(File.ReadAllText($"{_id}/Configuration.json")) ?? + = JsonSerializer.Deserialize>(File.ReadAllText(_configurationFile)) ?? new Dictionary(); if (Preferences.Keys.Count < DefaultPreferences.Keys.Count) @@ -53,7 +62,7 @@ public record GuildData { Preferences.TrimExcess(); MemberData = new Dictionary(); - foreach (var data in Directory.GetFiles($"{_id}/MemberData")) { + foreach (var data in Directory.GetFiles(memberDataDir)) { var deserialised = JsonSerializer.Deserialize(File.ReadAllText($"{_id}/MemberData/{data}.json")); MemberData.Add(deserialised!.Id, deserialised); @@ -88,7 +97,25 @@ public record GuildData { set => _cachedMuteRole = value; } - public static GuildData FromSocketGuild(SocketGuild guild) { + public SocketTextChannel? PublicFeedbackChannel { + get { + if (Preferences["PublicFeedbackChannel"] is "0") return null; + return _cachedPublicFeedbackChannel ??= Boyfriend.Client.GetGuild(_id).TextChannels + .Single(x => x.Id == ulong.Parse(Preferences["PublicFeedbackChannel"])); + } + set => _cachedPublicFeedbackChannel = value; + } + + public SocketTextChannel? PrivateFeedbackChannel { + get { + if (Preferences["PublicFeedbackChannel"] is "0") return null; + return _cachedPrivateFeedbackChannel ??= Boyfriend.Client.GetGuild(_id).TextChannels + .Single(x => x.Id == ulong.Parse(Preferences["PrivateFeedbackChannel"])); + } + set => _cachedPrivateFeedbackChannel = value; + } + + public static GuildData Get(SocketGuild guild) { if (GuildDataDictionary.TryGetValue(guild.Id, out var stored)) return stored; var newData = new GuildData(guild) { _id = guild.Id @@ -99,7 +126,7 @@ public record GuildData { public async Task Save(bool saveMemberData) { Preferences.TrimExcess(); - await File.WriteAllTextAsync($"{_id}/Configuration.json", + await File.WriteAllTextAsync(_configurationFile, JsonSerializer.Serialize(Preferences)); if (saveMemberData) foreach (var data in MemberData.Values) diff --git a/Boyfriend/Data/Reminder.cs b/Boyfriend/Data/Reminder.cs index 9d3d034..c64ebbd 100644 --- a/Boyfriend/Data/Reminder.cs +++ b/Boyfriend/Data/Reminder.cs @@ -3,4 +3,5 @@ public struct Reminder { public DateTimeOffset RemindAt; public string ReminderText; + public ulong ReminderChannel; } diff --git a/Boyfriend/EventHandler.cs b/Boyfriend/EventHandler.cs index e8108f8..fedddce 100644 --- a/Boyfriend/EventHandler.cs +++ b/Boyfriend/EventHandler.cs @@ -28,7 +28,7 @@ public static class EventHandler { var i = Random.Shared.Next(3); foreach (var guild in Client.Guilds) { - var config = GuildData.FromSocketGuild(guild).Preferences; + var config = GuildData.Get(guild).Preferences; var channel = guild.GetTextChannel(Utils.ParseMention(config["BotLogChannel"])); Utils.SetCurrentLanguage(guild); @@ -55,7 +55,8 @@ public static class EventHandler { await Task.Delay(500); var auditLogEntry = (await guild.GetAuditLogsAsync(1).FlattenAsync()).First(); - if (auditLogEntry.Data is MessageDeleteAuditLogData data && msg.Author.Id == data.Target.Id) + if (auditLogEntry.CreatedAt >= DateTimeOffset.Now.Subtract(TimeSpan.FromSeconds(1)) && + auditLogEntry.Data is MessageDeleteAuditLogData data && msg.Author.Id == data.Target.Id) mention = auditLogEntry.User.Mention; await Utils.SendFeedbackAsync(string.Format(Messages.CachedMessageDeleted, msg.Author.Mention, @@ -95,12 +96,12 @@ public static class EventHandler { private static async Task UserJoinedEvent(SocketGuildUser user) { var guild = user.Guild; - var data = GuildData.FromSocketGuild(guild); + var data = GuildData.Get(guild); var config = data.Preferences; Utils.SetCurrentLanguage(guild); if (config["SendWelcomeMessages"] is "true") - await Utils.SilentSendAsync(guild.SystemChannel, + await Utils.SilentSendAsync(data.PublicFeedbackChannel, string.Format(config["WelcomeMessage"] is "default" ? Messages.DefaultWelcomeMessage : config["WelcomeMessage"], user.Mention, guild.Name)); @@ -129,7 +130,7 @@ public static class EventHandler { } private static Task UserLeftEvent(SocketGuild guild, SocketUser user) { - var data = GuildData.FromSocketGuild(guild).MemberData[user.Id]; + var data = GuildData.Get(guild).MemberData[user.Id]; data.IsInGuild = false; data.LeftAt.Add(DateTimeOffset.Now); return Task.CompletedTask; @@ -137,7 +138,7 @@ public static class EventHandler { private static async Task ScheduledEventCreatedEvent(SocketGuildEvent scheduledEvent) { var guild = scheduledEvent.Guild; - var eventConfig = GuildData.FromSocketGuild(guild).Preferences; + var eventConfig = GuildData.Get(guild).Preferences; var channel = Utils.GetEventNotificationChannel(guild); Utils.SetCurrentLanguage(guild); @@ -161,7 +162,7 @@ public static class EventHandler { private static async Task ScheduledEventCancelledEvent(SocketGuildEvent scheduledEvent) { var guild = scheduledEvent.Guild; - var eventConfig = GuildData.FromSocketGuild(guild).Preferences; + var eventConfig = GuildData.Get(guild).Preferences; var channel = Utils.GetEventNotificationChannel(guild); Utils.SetCurrentLanguage(guild); if (channel is not null) @@ -171,7 +172,7 @@ public static class EventHandler { private static async Task ScheduledEventStartedEvent(SocketGuildEvent scheduledEvent) { var guild = scheduledEvent.Guild; - var eventConfig = GuildData.FromSocketGuild(guild).Preferences; + var eventConfig = GuildData.Get(guild).Preferences; var channel = Utils.GetEventNotificationChannel(guild); Utils.SetCurrentLanguage(guild); @@ -182,8 +183,9 @@ public static class EventHandler { 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} ")); + mentions = (await scheduledEvent.GetUsersAsync(15)) + .Where(user => role is null || !((RestGuildUser)user).RoleIds.Contains(role.Id)) + .Aggregate(mentions, (current, user) => current.Append($"{user.Mention} ")); await channel.SendMessageAsync(string.Format(Messages.EventStarted, mentions, Utils.Wrap(scheduledEvent.Name), diff --git a/Boyfriend/Messages.Designer.cs b/Boyfriend/Messages.Designer.cs index 197898a..7374f02 100644 --- a/Boyfriend/Messages.Designer.cs +++ b/Boyfriend/Messages.Designer.cs @@ -833,15 +833,6 @@ namespace Boyfriend { } } - /// - /// Looks up a localized string similar to Starter role. - /// - internal static string SettingsStarterRole { - get { - return ResourceManager.GetString("SettingsStarterRole", resourceCulture); - } - } - /// /// Looks up a localized string similar to Welcome message. /// @@ -851,6 +842,15 @@ namespace Boyfriend { } } + /// + /// Looks up a localized string similar to The starter role was deleted! Please unset roles or channels from settings before deleting them. + /// + internal static string StarterRoleDeleted { + get { + return ResourceManager.GetString("StarterRoleDeleted", resourceCulture); + } + } + /// /// Looks up a localized string similar to You cannot ban me!. /// diff --git a/Boyfriend/Messages.resx b/Boyfriend/Messages.resx index e892deb..47418d9 100644 --- a/Boyfriend/Messages.resx +++ b/Boyfriend/Messages.resx @@ -189,10 +189,7 @@ Send welcome messages - - Starter role - - + Mute role @@ -459,4 +456,7 @@ I could not find this user in any guild I'm a member of! Check if the ID is correct and that the user was on this server no longer than 30 days ago (TODO) + + The starter role was deleted! Please unset roles or channels from settings before deleting them + diff --git a/Boyfriend/Messages.ru.resx b/Boyfriend/Messages.ru.resx index d18eaf5..381ab2b 100644 --- a/Boyfriend/Messages.ru.resx +++ b/Boyfriend/Messages.ru.resx @@ -246,10 +246,7 @@ Я не могу использовать тайм-ауты на других ботах! Попробуй указать роль мута в настройках - - Начальная роль - - + {0} создал событие {1}! Оно пройдёт в {2} и начнётся <t:{3}:R>!{4} @@ -459,4 +456,7 @@ Я не смог найти этого пользователя ни в одном из серверов, в которых я есть. Проверь правильность ID и нахождение пользователя на этом сервере максимум 30 дней назад (TODO) + + Начальная роль была удалена! Пожалуйста сбрасывай роли или каналы перед тем как их удалить + diff --git a/Boyfriend/Messages.tt-ru.resx b/Boyfriend/Messages.tt-ru.resx index 046089b..543b803 100644 --- a/Boyfriend/Messages.tt-ru.resx +++ b/Boyfriend/Messages.tt-ru.resx @@ -246,10 +246,7 @@ я не могу замутить ботов, сделай что нибудь - - базовое звание - - + {0} приготовил новый квест {1}! он пройдёт в {2} и начнётся <t:{3}:R>!{4} @@ -459,4 +456,7 @@ TODO + + TODO + diff --git a/Boyfriend/Utils.cs b/Boyfriend/Utils.cs index 39705b1..b09f7d2 100644 --- a/Boyfriend/Utils.cs +++ b/Boyfriend/Utils.cs @@ -29,10 +29,6 @@ public static partial class Utils { return GetMessage($"Beep{(i < 0 ? Random.Shared.Next(3) + 1 : ++i)}"); } - public static SocketTextChannel? GetBotLogChannel(SocketGuild guild) { - return guild.GetTextChannel(ParseMention(GuildData.FromSocketGuild(guild).Preferences["BotLogChannel"])); - } - public static string? Wrap(string? original, bool limitedSpace = false) { if (original is null) return null; var maxChars = limitedSpace ? 970 : 1940; @@ -92,8 +88,9 @@ public static partial class Utils { public static async Task SendFeedbackAsync(string feedback, SocketGuild guild, string mention, bool sendPublic = false) { - var adminChannel = GetBotLogChannel(guild); - var systemChannel = guild.SystemChannel; + var data = GuildData.Get(guild); + var adminChannel = data.PrivateFeedbackChannel; + var systemChannel = data.PublicFeedbackChannel; var toSend = $"*[{mention}: {feedback}]*"; if (adminChannel is not null) await SilentSendAsync(adminChannel, toSend); if (sendPublic && systemChannel is not null) await SilentSendAsync(systemChannel, toSend); @@ -106,7 +103,7 @@ public static partial class Utils { } public static void SetCurrentLanguage(SocketGuild guild) { - Messages.Culture = CultureInfoCache[GuildData.FromSocketGuild(guild).Preferences["Lang"]]; + Messages.Culture = CultureInfoCache[GuildData.Get(guild).Preferences["Lang"]]; } public static void SafeAppendToBuilder(StringBuilder appendTo, string appendWhat, SocketTextChannel? channel) { @@ -129,7 +126,7 @@ public static partial class Utils { } public static SocketTextChannel? GetEventNotificationChannel(SocketGuild guild) { - return guild.GetTextChannel(ParseMention(GuildData.FromSocketGuild(guild) + return guild.GetTextChannel(ParseMention(GuildData.Get(guild) .Preferences["EventNotificationChannel"])); } @@ -141,6 +138,24 @@ public static partial class Utils { return GuildData.GuildDataDictionary.Values.Any(gData => gData.MemberData.Values.Any(mData => mData.Id == id)); } + public static async Task UnmuteMemberAsync(GuildData data, string modDiscrim, SocketGuildUser toUnmute, + string reason) { + var requestOptions = GetRequestOptions($"({modDiscrim}) {reason}"); + var role = data.MuteRole; + + if (role is not null) { + if (!toUnmute.Roles.Contains(role)) return false; + await toUnmute.AddRolesAsync(data.MemberData[toUnmute.Id].Roles, requestOptions); + await toUnmute.RemoveRoleAsync(role, requestOptions); + } else { + if (toUnmute.TimedOutUntil is null || toUnmute.TimedOutUntil.Value < DateTimeOffset.Now) return false; + + await toUnmute.RemoveTimeOutAsync(requestOptions); + } + + return true; + } + [GeneratedRegex("[^0-9]")] private static partial Regex NumbersOnlyRegex(); }