diff --git a/Myriad/Rest/Types/Requests/MessageRequest.cs b/Myriad/Rest/Types/Requests/MessageRequest.cs index c218c0fd..d403f8ae 100644 --- a/Myriad/Rest/Types/Requests/MessageRequest.cs +++ b/Myriad/Rest/Types/Requests/MessageRequest.cs @@ -11,5 +11,4 @@ public record MessageRequest public Embed[]? Embeds { get; set; } public MessageComponent[]? Components { get; set; } public Message.Reference? MessageReference { get; set; } - } \ No newline at end of file diff --git a/PluralKit.API/Controllers/PrivateController.cs b/PluralKit.API/Controllers/PrivateController.cs index 38ed9adb..a3c143c7 100644 --- a/PluralKit.API/Controllers/PrivateController.cs +++ b/PluralKit.API/Controllers/PrivateController.cs @@ -19,6 +19,7 @@ namespace PluralKit.API; public class PrivateController: PKControllerBase { private readonly RedisService _redis; + public PrivateController(IServiceProvider svc) : base(svc) { _redis = svc.GetRequiredService(); diff --git a/PluralKit.API/Startup.cs b/PluralKit.API/Startup.cs index 0ae577a8..fc9475c9 100644 --- a/PluralKit.API/Startup.cs +++ b/PluralKit.API/Startup.cs @@ -2,12 +2,9 @@ using System.Reflection; using Autofac; -using App.Metrics.AspNetCore; - using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Diagnostics; -using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.OpenApi.Models; using Newtonsoft.Json; @@ -100,7 +97,9 @@ public class Startup .As(); builder.RegisterModule(new ConfigModule("API")); builder.RegisterModule(new LoggingModule("api", - cfg: new LoggerConfiguration().Filter.ByExcluding(exc => exc.Exception is PKError || exc.Exception.IsUserError()))); + cfg: new LoggerConfiguration().Filter.ByExcluding( + exc => exc.Exception is PKError || exc.Exception.IsUserError() + ))); // builder.RegisterModule(new MetricsModule("API")); builder.RegisterModule(); builder.RegisterModule(); diff --git a/PluralKit.Bot/Bot.cs b/PluralKit.Bot/Bot.cs index f93475d0..d61cf8fa 100644 --- a/PluralKit.Bot/Bot.cs +++ b/PluralKit.Bot/Bot.cs @@ -1,5 +1,3 @@ -using System.Net.WebSockets; - using App.Metrics; using Autofac; @@ -123,7 +121,11 @@ public class Bot { Activities = new[] { - new Activity {Name = "Restarting... (please wait)", Type = ActivityType.Game} + new Activity + { + Name = "Restarting... (please wait)", + Type = ActivityType.Game + } }, Status = GatewayStatusUpdate.UserStatus.Idle }))); diff --git a/PluralKit.Bot/BotMetrics.cs b/PluralKit.Bot/BotMetrics.cs index 832a2b84..42d8b64b 100644 --- a/PluralKit.Bot/BotMetrics.cs +++ b/PluralKit.Bot/BotMetrics.cs @@ -1,5 +1,4 @@ using App.Metrics; -using App.Metrics.Gauge; using App.Metrics.Meter; using App.Metrics.Timer; diff --git a/PluralKit.Bot/CommandMeta/CommandParseErrors.cs b/PluralKit.Bot/CommandMeta/CommandParseErrors.cs index 5e918e76..522aab14 100644 --- a/PluralKit.Bot/CommandMeta/CommandParseErrors.cs +++ b/PluralKit.Bot/CommandMeta/CommandParseErrors.cs @@ -12,6 +12,7 @@ public partial class CommandTree await ctx.Reply( $"{Emojis.Error} Unknown command `pk;{ctx.FullCommand().Truncate(100)}`. Perhaps you meant to use one of the following commands?\n{commandListStr}\n\nFor a full list of possible commands, see ."); } + private async Task PrintCommandExpectedError(Context ctx, params Command[] potentialCommands) { var commandListStr = CreatePotentialCommandList(potentialCommands); diff --git a/PluralKit.Bot/Commands/Autoproxy.cs b/PluralKit.Bot/Commands/Autoproxy.cs index db0af3ba..8a5718f9 100644 --- a/PluralKit.Bot/Commands/Autoproxy.cs +++ b/PluralKit.Bot/Commands/Autoproxy.cs @@ -1,10 +1,6 @@ -using Humanizer; - using Myriad.Builders; using Myriad.Types; -using NodaTime; - using PluralKit.Core; namespace PluralKit.Bot; diff --git a/PluralKit.Bot/Commands/Groups.cs b/PluralKit.Bot/Commands/Groups.cs index cc19f016..4b92f369 100644 --- a/PluralKit.Bot/Commands/Groups.cs +++ b/PluralKit.Bot/Commands/Groups.cs @@ -1,15 +1,11 @@ using System.Text; using System.Text.RegularExpressions; -using Humanizer; - using Myriad.Builders; using Myriad.Types; using Newtonsoft.Json.Linq; -using NodaTime; - using PluralKit.Core; namespace PluralKit.Bot; diff --git a/PluralKit.Bot/Commands/ImportExport.cs b/PluralKit.Bot/Commands/ImportExport.cs index 046e9ce2..36722357 100644 --- a/PluralKit.Bot/Commands/ImportExport.cs +++ b/PluralKit.Bot/Commands/ImportExport.cs @@ -1,6 +1,5 @@ using System.Text; -using Myriad.Extensions; using Myriad.Rest.Exceptions; using Myriad.Rest.Types; using Myriad.Rest.Types.Requests; diff --git a/PluralKit.Bot/Commands/Lists/ContextListExt.cs b/PluralKit.Bot/Commands/Lists/ContextListExt.cs index 29af66dd..a1f62548 100644 --- a/PluralKit.Bot/Commands/Lists/ContextListExt.cs +++ b/PluralKit.Bot/Commands/Lists/ContextListExt.cs @@ -5,8 +5,6 @@ using Humanizer; using Myriad.Builders; using Myriad.Types; -using NodaTime; - using PluralKit.Core; namespace PluralKit.Bot; diff --git a/PluralKit.Bot/Commands/MemberEdit.cs b/PluralKit.Bot/Commands/MemberEdit.cs index af9cfbad..9a2bcdd1 100644 --- a/PluralKit.Bot/Commands/MemberEdit.cs +++ b/PluralKit.Bot/Commands/MemberEdit.cs @@ -323,6 +323,7 @@ public class MemberEdit } private string boldIf(string str, bool condition) => condition ? $"**{str}**" : str; + private async Task CreateMemberNameInfoEmbed(Context ctx, PKMember target) { var lcx = ctx.LookupContextFor(target.System); diff --git a/PluralKit.Bot/Commands/Message.cs b/PluralKit.Bot/Commands/Message.cs index b00be8d1..199d452e 100644 --- a/PluralKit.Bot/Commands/Message.cs +++ b/PluralKit.Bot/Commands/Message.cs @@ -20,6 +20,7 @@ namespace PluralKit.Bot; public class ProxiedMessage { private static readonly Duration EditTimeout = Duration.FromMinutes(10); + // private readonly IDiscordCache _cache; private readonly IClock _clock; diff --git a/PluralKit.Bot/Commands/SystemEdit.cs b/PluralKit.Bot/Commands/SystemEdit.cs index 8e38f86c..1e5f09f8 100644 --- a/PluralKit.Bot/Commands/SystemEdit.cs +++ b/PluralKit.Bot/Commands/SystemEdit.cs @@ -3,10 +3,6 @@ using System.Text.RegularExpressions; using Myriad.Builders; using Myriad.Types; -using NodaTime; -using NodaTime.Text; -using NodaTime.TimeZones; - using PluralKit.Core; namespace PluralKit.Bot; @@ -479,9 +475,10 @@ public class SystemEdit } else { - throw new PKSyntaxError( - "This system does not have a banner image set." + (isOwnSystem ? "Set one by attaching an image to this command, or by passing an image URL or @mention." : "")); + throw new PKSyntaxError("This system does not have a banner image set." + + (isOwnSystem ? "Set one by attaching an image to this command, or by passing an image URL or @mention." : "")); } + return; } @@ -514,7 +511,6 @@ public class SystemEdit ? ctx.Reply(msg, new EmbedBuilder().Image(new Embed.EmbedImage(img.Url)).Build()) : ctx.Reply(msg)); } - } public async Task Delete(Context ctx, PKSystem target) diff --git a/PluralKit.Bot/Handlers/MessageCreated.cs b/PluralKit.Bot/Handlers/MessageCreated.cs index 0ca4250d..2bab31e5 100644 --- a/PluralKit.Bot/Handlers/MessageCreated.cs +++ b/PluralKit.Bot/Handlers/MessageCreated.cs @@ -52,12 +52,7 @@ public class MessageCreated: IEventHandler _dmCache = dmCache; } - // for now, only return error messages for explicit commands - public ulong? ErrorChannelFor(MessageCreateEvent evt, ulong userId) - { - return evt.ChannelId; - } - + public ulong? ErrorChannelFor(MessageCreateEvent evt, ulong userId) => evt.ChannelId; private bool IsDuplicateMessage(Message msg) => // We consider a message duplicate if it has the same ID as the previous message that hit the gateway _lastMessageCache.GetLastMessage(msg.ChannelId)?.Current.Id == msg.Id; diff --git a/PluralKit.Bot/Proxy/ProxyService.cs b/PluralKit.Bot/Proxy/ProxyService.cs index 64c9b067..81a7debd 100644 --- a/PluralKit.Bot/Proxy/ProxyService.cs +++ b/PluralKit.Bot/Proxy/ProxyService.cs @@ -63,7 +63,8 @@ public class ProxyService if (autoproxySettings.AutoproxyMode == AutoproxyMode.Latch && IsUnlatch(message)) { // "unlatch" - await _repo.UpdateAutoproxy(ctx.SystemId.Value, guild.Id, null, new() { + await _repo.UpdateAutoproxy(ctx.SystemId.Value, guild.Id, null, new() + { AutoproxyMember = null }); return false; diff --git a/PluralKit.Bot/Services/ErrorMessageService.cs b/PluralKit.Bot/Services/ErrorMessageService.cs index 9b151f86..bf92fc87 100644 --- a/PluralKit.Bot/Services/ErrorMessageService.cs +++ b/PluralKit.Bot/Services/ErrorMessageService.cs @@ -18,8 +18,8 @@ public class ErrorMessageService // globally rate limit errors for now, don't want to spam users when something breaks private static readonly Duration MinErrorInterval = Duration.FromSeconds(10); private static readonly Duration IntervalFromStartup = Duration.FromMinutes(2); - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly BotConfig _botConfig; private readonly IMetrics _metrics; private readonly DiscordApiClient _rest; diff --git a/PluralKit.Bot/Services/PrivateChannelService.cs b/PluralKit.Bot/Services/PrivateChannelService.cs index 4daa58cb..e5b4fa3c 100644 --- a/PluralKit.Bot/Services/PrivateChannelService.cs +++ b/PluralKit.Bot/Services/PrivateChannelService.cs @@ -1,6 +1,5 @@ using Serilog; -using Myriad.Cache; using Myriad.Gateway; using Myriad.Rest; @@ -10,11 +9,11 @@ namespace PluralKit.Bot; public class PrivateChannelService { + private static readonly Dictionary _channelsCache = new(); + private readonly ILogger _logger; private readonly ModelRepository _repo; private readonly DiscordApiClient _rest; - - private static Dictionary _channelsCache = new(); public PrivateChannelService(ILogger logger, ModelRepository repo, DiscordApiClient rest) { _logger = logger; diff --git a/PluralKit.Bot/Utils/ContextUtils.cs b/PluralKit.Bot/Utils/ContextUtils.cs index 5060dabb..79b94c3a 100644 --- a/PluralKit.Bot/Utils/ContextUtils.cs +++ b/PluralKit.Bot/Utils/ContextUtils.cs @@ -169,7 +169,8 @@ public static class ContextUtils if (currentPage < 0) currentPage += pageCount; // If we can, remove the user's reaction (so they can press again quickly) - if ((await ctx.BotPermissions).HasFlag(PermissionSet.ManageMessages)) try + if ((await ctx.BotPermissions).HasFlag(PermissionSet.ManageMessages)) + try { await ctx.Rest.DeleteUserReaction(msg.ChannelId, msg.Id, reaction.Emoji, reaction.UserId); } diff --git a/PluralKit.Core/Database/DatabaseQueries.cs b/PluralKit.Core/Database/DatabaseQueries.cs index 4d0b7a03..a41e101b 100644 --- a/PluralKit.Core/Database/DatabaseQueries.cs +++ b/PluralKit.Core/Database/DatabaseQueries.cs @@ -5,8 +5,6 @@ using App.Metrics; using Dapper; -using Npgsql; - using SqlKata; namespace PluralKit.Core; @@ -82,8 +80,10 @@ internal partial class Database: IDatabase var query = _compiler.Compile(q); using var conn = await Obtain(); using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) + { await foreach (var val in conn.QueryStreamAsync(query.Sql, query.NamedBindings)) yield return val; + } } // the procedures (message_context and proxy_members, as of writing) have their own metrics tracking elsewhere diff --git a/PluralKit.Core/Database/Functions/functions.sql b/PluralKit.Core/Database/Functions/functions.sql index 32c8a28c..bebfd7b3 100644 --- a/PluralKit.Core/Database/Functions/functions.sql +++ b/PluralKit.Core/Database/Functions/functions.sql @@ -27,22 +27,22 @@ as $$ where accounts.uid = account_id), guild as (select * from servers where id = guild_id) select - system.id as system_id, + system.id as system_id, system.is_deleting, guild.log_channel, - (channel_id = any(guild.blacklist)) as in_blacklist, - (channel_id = any(guild.log_blacklist)) as in_log_blacklist, + (channel_id = any (guild.blacklist)) as in_blacklist, + (channel_id = any (guild.log_blacklist)) as in_log_blacklist, coalesce(guild.log_cleanup_enabled, false), coalesce(system_guild.proxy_enabled, true) as proxy_enabled, - system_last_switch.switch as last_switch, - system_last_switch.members as last_switch_members, - system_last_switch.timestamp as last_switch_timestamp, - system.tag as system_tag, - system.guild_tag as system_guild_tag, - coalesce(system.tag_enabled, true) as tag_enabled, - system.avatar_url as system_avatar, - system.account_autoproxy as allow_autoproxy, - system.latch_timeout as latch_timeout + system_last_switch.switch as last_switch, + system_last_switch.members as last_switch_members, + system_last_switch.timestamp as last_switch_timestamp, + system.tag as system_tag, + system.guild_tag as system_guild_tag, + coalesce(system.tag_enabled, true) as tag_enabled, + system.avatar_url as system_avatar, + system.account_autoproxy as allow_autoproxy, + system.latch_timeout as latch_timeout -- We need a "from" clause, so we just use some bogus data that's always present -- This ensure we always have exactly one row going forward, so we can left join afterwards and still get data from (select 1) as _placeholder @@ -60,7 +60,7 @@ create function proxy_members(account_id bigint, guild_id bigint) id int, proxy_tags proxy_tag[], keep_proxy bool, - + server_name text, display_name text, name text, @@ -75,22 +75,22 @@ create function proxy_members(account_id bigint, guild_id bigint) as $$ select -- Basic data - members.id as id, - members.proxy_tags as proxy_tags, - members.keep_proxy as keep_proxy, - + members.id as id, + members.proxy_tags as proxy_tags, + members.keep_proxy as keep_proxy, + -- Name info member_guild.display_name as server_name, - members.display_name as display_name, - members.name as name, - + members.display_name as display_name, + members.name as name, + -- Avatar info - member_guild.avatar_url as server_avatar, - members.avatar_url as avatar, + member_guild.avatar_url as server_avatar, + members.avatar_url as avatar, - members.color as color, + members.color as color, - members.allow_autoproxy as allow_autoproxy + members.allow_autoproxy as allow_autoproxy from accounts inner join systems on systems.id = accounts.system inner join members on members.system = systems.id diff --git a/PluralKit.Core/Database/Views/views.sql b/PluralKit.Core/Database/Views/views.sql index b62637afb..f936eaf2 100644 --- a/PluralKit.Core/Database/Views/views.sql +++ b/PluralKit.Core/Database/Views/views.sql @@ -1,6 +1,6 @@ -- Returns one row per system, containing info about latest switch + array of member IDs (for future joins) create view system_last_switch as -select systems.id as system, +select systems.id as system, last_switch.id as switch, last_switch.timestamp as timestamp, array(select member from switch_members where switch_members.switch = last_switch.id order by switch_members.id) as members @@ -10,16 +10,16 @@ from systems -- Returns one row for every current fronter in a system, w/ some member info create view system_fronters as select - systems.id as system_id, - last_switch.id as switch_id, + systems.id as system_id, + last_switch.id as switch_id, last_switch.timestamp as switch_timestamp, - members.id as member_id, - members.hid as member_hid, - members.name as member_name + members.id as member_id, + members.hid as member_hid, + members.name as member_name from systems -- TODO: is there a more efficient way of doing this search? might need to index on timestamp if we haven't in prod inner join lateral (select * from switches where switches.system = systems.id order by timestamp desc limit 1) as last_switch on true - + -- change to left join to handle memberless switches? inner join switch_members on switch_members.switch = last_switch.system inner join members on members.id = switch_members.member @@ -30,8 +30,8 @@ create view member_list as select members.*, -- Find last message ID -- max(mid) does full table scan, order by/limit uses index (dunno why, but it works!) - -- (select mid from messages where messages.member = members.id order by mid desc nulls last limit 1) as last_message, - + -- (select mid from messages where messages.member = members.id order by mid desc nulls last limit 1) as last_message, + -- Find last switch timestamp ( select max(switches.timestamp) @@ -39,20 +39,20 @@ select members.*, inner join switches on switches.id = switch_members.switch where switch_members.member = members.id ) as last_switch_time, - + -- Extract month/day from birthday and "force" the year identical (just using 4) -> month/day only sorting! - case when members.birthday is not null then - make_date( - 4, - extract(month from members.birthday)::integer, - extract(day from members.birthday)::integer - ) end as birthday_md, + case when members.birthday is not null then + make_date( + 4, + extract(month from members.birthday)::integer, + extract(day from members.birthday)::integer + ) end as birthday_md, -- Extract member description as seen by "the public" - case - -- Privacy '1' = public; just return description as normal - when members.description_privacy = 1 then members.description - -- Any other privacy (rn just '2'), return null description (missing case = null in SQL) + case + -- Privacy '1' = public; just return description as normal + when members.description_privacy = 1 then members.description + -- Any other privacy (rn just '2'), return null description (missing case = null in SQL) end as public_description from members; @@ -60,16 +60,16 @@ create view group_list as select groups.*, -- Find public group member count ( - select count(*) from group_members - inner join members on group_members.member_id = members.id - where + select count(*) from group_members + inner join members on group_members.member_id = members.id + where group_members.group_id = groups.id and members.member_visibility = 1 ) as public_member_count, -- Find private group member count ( - select count(*) from group_members - inner join members on group_members.member_id = members.id - where + select count(*) from group_members + inner join members on group_members.member_id = members.id + where group_members.group_id = groups.id ) as total_member_count from groups; \ No newline at end of file diff --git a/PluralKit.Core/Models/ModelTypes/Partial.cs b/PluralKit.Core/Models/ModelTypes/Partial.cs index d4c201d4..ce6eaf67 100644 --- a/PluralKit.Core/Models/ModelTypes/Partial.cs +++ b/PluralKit.Core/Models/ModelTypes/Partial.cs @@ -1,8 +1,6 @@ #nullable enable using System.Collections; -using Dapper; - using Newtonsoft.Json; namespace PluralKit.Core; diff --git a/PluralKit.Core/Models/PKSystem.cs b/PluralKit.Core/Models/PKSystem.cs index ce992d55..7d5748d9 100644 --- a/PluralKit.Core/Models/PKSystem.cs +++ b/PluralKit.Core/Models/PKSystem.cs @@ -1,6 +1,5 @@ using Dapper.Contrib.Extensions; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NodaTime; @@ -90,7 +89,8 @@ public static class PKSystemExt ctx == LookupContext.ByOwner ? system.DescriptionPrivacy.ToJsonString() : null); o.Add("member_list_privacy", ctx == LookupContext.ByOwner ? system.MemberListPrivacy.ToJsonString() : null); - o.Add("group_list_privacy", ctx == LookupContext.ByOwner ? system.GroupListPrivacy.ToJsonString() : null); + o.Add("group_list_privacy", + ctx == LookupContext.ByOwner ? system.GroupListPrivacy.ToJsonString() : null); o.Add("front_privacy", ctx == LookupContext.ByOwner ? system.FrontPrivacy.ToJsonString() : null); o.Add("front_history_privacy", ctx == LookupContext.ByOwner ? system.FrontHistoryPrivacy.ToJsonString() : null); diff --git a/PluralKit.Core/Models/Patch/AutoproxyPatch.cs b/PluralKit.Core/Models/Patch/AutoproxyPatch.cs index 2016a4fa..0f42bc5a 100644 --- a/PluralKit.Core/Models/Patch/AutoproxyPatch.cs +++ b/PluralKit.Core/Models/Patch/AutoproxyPatch.cs @@ -1,5 +1,3 @@ -using Newtonsoft.Json.Linq; - using NodaTime; using SqlKata; diff --git a/PluralKit.Core/Models/Patch/SystemPatch.cs b/PluralKit.Core/Models/Patch/SystemPatch.cs index 855ce8fd..f0778399 100644 --- a/PluralKit.Core/Models/Patch/SystemPatch.cs +++ b/PluralKit.Core/Models/Patch/SystemPatch.cs @@ -1,8 +1,6 @@ #nullable enable using Newtonsoft.Json.Linq; -using NodaTime; - using SqlKata; namespace PluralKit.Core; diff --git a/PluralKit.Core/Modules/LoggingModule.cs b/PluralKit.Core/Modules/LoggingModule.cs index 00b662f4..0f301863 100644 --- a/PluralKit.Core/Modules/LoggingModule.cs +++ b/PluralKit.Core/Modules/LoggingModule.cs @@ -24,6 +24,7 @@ public class LoggingModule: Module public LoggingModule(string component, Action fn = null, LoggerConfiguration cfg = null) { _component = component; + // todo: this is messy and not really used anywhere...? _fn = fn ?? (_ => { }); _cfg = cfg ?? new LoggerConfiguration(); } diff --git a/PluralKit.Core/Utils/Limits.cs b/PluralKit.Core/Utils/Limits.cs index 24bd5af7..4e484664 100644 --- a/PluralKit.Core/Utils/Limits.cs +++ b/PluralKit.Core/Utils/Limits.cs @@ -9,6 +9,7 @@ public static class Limits public static readonly int MaxMemberCount = 1000; public static readonly int MaxGroupCount = 250; public static int WarnThreshold(int limit) => limit - 50; + public static readonly int MaxDescriptionLength = 1000; public static readonly int MaxProxyTagLength = 100; public static readonly int MaxSwitchMemberCount = 150; diff --git a/PluralKit.Core/Utils/ProtobufUtils.cs b/PluralKit.Core/Utils/ProtobufUtils.cs index 9ab45dd4..63cd9374 100644 --- a/PluralKit.Core/Utils/ProtobufUtils.cs +++ b/PluralKit.Core/Utils/ProtobufUtils.cs @@ -4,7 +4,7 @@ namespace PluralKit.Core; public static class Proto { - private static Dictionary _parser = new(); + private static readonly Dictionary _parser = new(); public static byte[] Marshal(this IMessage message) => message.ToByteArray(); @@ -12,11 +12,11 @@ public static class Proto { var type = typeof(T).ToString(); if (_parser.ContainsKey(type)) - return (T)_parser[type].ParseFrom(message); - else { - _parser.Add(type, new MessageParser(() => new T())); - return Unmarshal(message); + return (T)_parser[type].ParseFrom(message); } + + _parser.Add(type, new MessageParser(() => new T())); + return Unmarshal(message); } } \ No newline at end of file diff --git a/PluralKit.ScheduledTasks/Metrics.cs b/PluralKit.ScheduledTasks/Metrics.cs index 461f7351..d6111e20 100644 --- a/PluralKit.ScheduledTasks/Metrics.cs +++ b/PluralKit.ScheduledTasks/Metrics.cs @@ -22,5 +22,4 @@ public static class Metrics Context = "Bot", MeasurementUnit = Unit.Items }; - } \ No newline at end of file