diff --git a/PluralKit.API/packages.lock.json b/PluralKit.API/packages.lock.json index cde6cbf4..dcd71ead 100644 --- a/PluralKit.API/packages.lock.json +++ b/PluralKit.API/packages.lock.json @@ -217,6 +217,11 @@ "System.Diagnostics.DiagnosticSource": "4.5.1" } }, + "Humanizer.Core": { + "type": "Transitive", + "resolved": "2.8.26", + "contentHash": "OiKusGL20vby4uDEswj2IgkdchC1yQ6rwbIkZDVBPIR6al2b7n3pC91elBul9q33KaBgRKhbZH3+2Ur4fnWx2A==" + }, "Microsoft.AspNetCore.JsonPatch": { "type": "Transitive", "resolved": "3.1.0", @@ -796,6 +801,24 @@ "System.Threading.Timer": "4.0.1" } }, + "SqlKata": { + "type": "Transitive", + "resolved": "2.3.7", + "contentHash": "erKffEMhrS2IFKXjYV83M4uc1IOCl91yeP/3uY5yIm6pRNFDNrqnTk3La1en6EGDlMRol9abTNO1erQCYf08tg==", + "dependencies": { + "System.Collections.Concurrent": "4.3.0" + } + }, + "SqlKata.Execution": { + "type": "Transitive", + "resolved": "2.3.7", + "contentHash": "LybTYj99riLRH7YQNt9Kuc8VpZOvaQ7H4sQBrj2zefktS8LASOaXsHRYC/k8NEcj25w6huQpOi+HrEZ5qHXl0w==", + "dependencies": { + "Humanizer.Core": "2.8.26", + "SqlKata": "2.3.7", + "dapper": "1.50.5" + } + }, "Swashbuckle.AspNetCore": { "type": "Transitive", "resolved": "5.0.0", @@ -1575,6 +1598,8 @@ "Serilog.Sinks.Console": "4.0.0-dev-00834", "Serilog.Sinks.Elasticsearch": "8.4.1", "Serilog.Sinks.File": "4.1.0", + "SqlKata": "2.3.7", + "SqlKata.Execution": "2.3.7", "System.Interactive.Async": "5.0.0" } } diff --git a/PluralKit.Bot/Commands/Admin.cs b/PluralKit.Bot/Commands/Admin.cs index db563da9..984b0919 100644 --- a/PluralKit.Bot/Commands/Admin.cs +++ b/PluralKit.Bot/Commands/Admin.cs @@ -31,7 +31,7 @@ namespace PluralKit.Bot if (!Regex.IsMatch(newHid, "^[a-z]{5}$")) throw new PKError($"Invalid new system ID `{newHid}`."); - var existingSystem = _repo.GetSystemByHid(newHid); + var existingSystem = await _repo.GetSystemByHid(newHid); if (existingSystem != null) throw new PKError($"Another system already exists with ID `{newHid}`."); @@ -77,7 +77,7 @@ namespace PluralKit.Bot if (!Regex.IsMatch(newHid, "^[a-z]{5}$")) throw new PKError($"Invalid new group ID `{newHid}`."); - var existingGroup = _repo.GetGroupByHid(newHid); + var existingGroup = await _repo.GetGroupByHid(newHid); if (existingGroup != null) throw new PKError($"Another group already exists with ID `{newHid}`."); diff --git a/PluralKit.Bot/Commands/Message.cs b/PluralKit.Bot/Commands/Message.cs index 6f7ba28f..0f8bc225 100644 --- a/PluralKit.Bot/Commands/Message.cs +++ b/PluralKit.Bot/Commands/Message.cs @@ -150,6 +150,9 @@ namespace PluralKit.Bot if (ctx.Guild != null) await ctx.Rest.DeleteMessage(ctx.Message); + else + await ctx.Rest.CreateReaction(ctx.Message.ChannelId, ctx.Message.Id, new() { Name = Emojis.Success }); + return; } if (ctx.Match("author") || ctx.MatchFlag("author")) diff --git a/PluralKit.Bot/Commands/SystemFront.cs b/PluralKit.Bot/Commands/SystemFront.cs index 201a258a..b813ced3 100644 --- a/PluralKit.Bot/Commands/SystemFront.cs +++ b/PluralKit.Bot/Commands/SystemFront.cs @@ -100,7 +100,7 @@ namespace PluralKit.Bot $"**{membersStr}** ({sw.Timestamp.FormatZoned(system.Zone)}, {switchSince.FormatDuration()} ago)\n"; } - if (sb.Length + stringToAdd.Length >= 1024) + if (sb.Length + stringToAdd.Length >= 4096) break; sb.Append(stringToAdd); } diff --git a/PluralKit.Bot/Proxy/ProxyService.cs b/PluralKit.Bot/Proxy/ProxyService.cs index 74d61293..fa59578c 100644 --- a/PluralKit.Bot/Proxy/ProxyService.cs +++ b/PluralKit.Bot/Proxy/ProxyService.cs @@ -230,7 +230,7 @@ namespace PluralKit.Bot var username = nickname ?? repliedTo.Author.Username; var avatarUrl = avatar != null - ? $"https://cdn.discordapp.com/guilds/{trigger.GuildId}/users/{repliedTo.Author.Id}/{avatar}.png" + ? $"https://cdn.discordapp.com/guilds/{trigger.GuildId}/users/{repliedTo.Author.Id}/avatars/{avatar}.png" : $"https://cdn.discordapp.com/avatars/{repliedTo.Author.Id}/{repliedTo.Author.Avatar}.png"; return new Embed diff --git a/PluralKit.Bot/packages.lock.json b/PluralKit.Bot/packages.lock.json index be4cd0f8..edb3e3e7 100644 --- a/PluralKit.Bot/packages.lock.json +++ b/PluralKit.Bot/packages.lock.json @@ -623,6 +623,24 @@ "System.Threading.Timer": "4.0.1" } }, + "SqlKata": { + "type": "Transitive", + "resolved": "2.3.7", + "contentHash": "erKffEMhrS2IFKXjYV83M4uc1IOCl91yeP/3uY5yIm6pRNFDNrqnTk3La1en6EGDlMRol9abTNO1erQCYf08tg==", + "dependencies": { + "System.Collections.Concurrent": "4.3.0" + } + }, + "SqlKata.Execution": { + "type": "Transitive", + "resolved": "2.3.7", + "contentHash": "LybTYj99riLRH7YQNt9Kuc8VpZOvaQ7H4sQBrj2zefktS8LASOaXsHRYC/k8NEcj25w6huQpOi+HrEZ5qHXl0w==", + "dependencies": { + "Humanizer.Core": "2.8.26", + "SqlKata": "2.3.7", + "dapper": "1.50.5" + } + }, "System.AppContext": { "type": "Transitive", "resolved": "4.3.0", @@ -1378,6 +1396,8 @@ "Serilog.Sinks.Console": "4.0.0-dev-00834", "Serilog.Sinks.Elasticsearch": "8.4.1", "Serilog.Sinks.File": "4.1.0", + "SqlKata": "2.3.7", + "SqlKata.Execution": "2.3.7", "System.Interactive.Async": "5.0.0" } } diff --git a/PluralKit.Core/Database/Database.cs b/PluralKit.Core/Database/Database.cs index de98f468..679674b3 100644 --- a/PluralKit.Core/Database/Database.cs +++ b/PluralKit.Core/Database/Database.cs @@ -186,6 +186,16 @@ namespace PluralKit.Core return await conn.ExecuteAsync(query.Sql + $" {extraSql}", query.NamedBindings); } + public async Task ExecuteQuery(IPKConnection? conn, Query q, string extraSql = "", [CallerMemberName] string queryName = "") + { + if (conn == null) + return await ExecuteQuery(q, extraSql, queryName); + + var query = _compiler.Compile(q); + using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName))) + return await conn.ExecuteAsync(query.Sql + $" {extraSql}", query.NamedBindings); + } + public async Task QueryFirst(Query q, string extraSql = "", [CallerMemberName] string queryName = "") { var query = _compiler.Compile(q); diff --git a/PluralKit.Core/Database/IDatabase.cs b/PluralKit.Core/Database/IDatabase.cs index 6c48d6be..ead9458c 100644 --- a/PluralKit.Core/Database/IDatabase.cs +++ b/PluralKit.Core/Database/IDatabase.cs @@ -15,6 +15,7 @@ namespace PluralKit.Core Task Execute(Func> func); IAsyncEnumerable Execute(Func> func); Task ExecuteQuery(Query q, string extraSql = "", [CallerMemberName] string queryName = ""); + Task ExecuteQuery(IPKConnection? conn, Query q, string extraSql = "", [CallerMemberName] string queryName = ""); Task QueryFirst(Query q, string extraSql = "", [CallerMemberName] string queryName = ""); Task QueryFirst(IPKConnection? conn, Query q, string extraSql = "", [CallerMemberName] string queryName = ""); Task> Query(Query q, [CallerMemberName] string queryName = ""); diff --git a/PluralKit.Core/Database/Repository/ModelRepository.Account.cs b/PluralKit.Core/Database/Repository/ModelRepository.Account.cs index a0c606dc..bba07815 100644 --- a/PluralKit.Core/Database/Repository/ModelRepository.Account.cs +++ b/PluralKit.Core/Database/Repository/ModelRepository.Account.cs @@ -10,7 +10,7 @@ namespace PluralKit.Core { _logger.Information("Updated account {accountId}: {@AccountPatch}", id, patch); var query = patch.Apply(new Query("accounts").Where("uid", id)); - await _db.ExecuteQuery(query); + await _db.ExecuteQuery(query, extraSql: "returning *"); } } } \ No newline at end of file diff --git a/PluralKit.Core/Database/Repository/ModelRepository.Guild.cs b/PluralKit.Core/Database/Repository/ModelRepository.Guild.cs index 538fce39..5eb8ed26 100644 --- a/PluralKit.Core/Database/Repository/ModelRepository.Guild.cs +++ b/PluralKit.Core/Database/Repository/ModelRepository.Guild.cs @@ -17,7 +17,7 @@ namespace PluralKit.Core { _logger.Information("Updated guild {GuildId}: {@GuildPatch}", guild, patch); var query = patch.Apply(new Query("servers").Where("id", guild)); - return _db.ExecuteQuery(query); + return _db.ExecuteQuery(query, extraSql: "returning *"); } @@ -37,7 +37,7 @@ namespace PluralKit.Core { _logger.Information("Updated {SystemId} in guild {GuildId}: {@SystemGuildPatch}", system, guild, patch); var query = patch.Apply(new Query("system_guild").Where("system", system).Where("guild", guild)); - return _db.ExecuteQuery(query); + return _db.ExecuteQuery(query, extraSql: "returning *"); } @@ -57,7 +57,7 @@ namespace PluralKit.Core { _logger.Information("Updated {MemberId} in guild {GuildId}: {@MemberGuildPatch}", member, guild, patch); var query = patch.Apply(new Query("member_guild").Where("member", member).Where("guild", guild)); - return _db.ExecuteQuery(query); + return _db.ExecuteQuery(query, extraSql: "returning *"); } } } \ No newline at end of file diff --git a/PluralKit.Core/Database/Repository/ModelRepository.Member.cs b/PluralKit.Core/Database/Repository/ModelRepository.Member.cs index 646a5235..d2cf4e4f 100644 --- a/PluralKit.Core/Database/Repository/ModelRepository.Member.cs +++ b/PluralKit.Core/Database/Repository/ModelRepository.Member.cs @@ -64,7 +64,7 @@ namespace PluralKit.Core { _logger.Information("Updated {MemberId}: {@MemberPatch}", id, patch); var query = patch.Apply(new Query("members").Where("id", id)); - return _db.QueryFirst(conn, query); + return _db.QueryFirst(conn, query, extraSql: "returning *"); } public Task DeleteMember(MemberId id) diff --git a/PluralKit.Core/Database/Repository/ModelRepository.System.cs b/PluralKit.Core/Database/Repository/ModelRepository.System.cs index a9a48e28..805892c9 100644 --- a/PluralKit.Core/Database/Repository/ModelRepository.System.cs +++ b/PluralKit.Core/Database/Repository/ModelRepository.System.cs @@ -88,7 +88,7 @@ namespace PluralKit.Core return _db.QueryFirst(conn, query, extraSql: "returning *"); } - public Task AddAccount(SystemId system, ulong accountId) + public Task AddAccount(SystemId system, ulong accountId, IPKConnection? conn = null) { // We have "on conflict do nothing" since linking an account when it's already linked to the same system is idempotent // This is used in import/export, although the pk;link command checks for this case beforehand @@ -100,7 +100,7 @@ namespace PluralKit.Core }); _logger.Information("Linked account {UserId} to {SystemId}", accountId, system); - return _db.ExecuteQuery(query, extraSql: "on conflict do nothing"); + return _db.ExecuteQuery(conn, query, extraSql: "on conflict do nothing"); } public async Task RemoveAccount(SystemId system, ulong accountId) diff --git a/PluralKit.Core/Utils/BulkImporter/BulkImporter.cs b/PluralKit.Core/Utils/BulkImporter/BulkImporter.cs index 5ad0297e..c7bae342 100644 --- a/PluralKit.Core/Utils/BulkImporter/BulkImporter.cs +++ b/PluralKit.Core/Utils/BulkImporter/BulkImporter.cs @@ -49,7 +49,7 @@ namespace PluralKit.Core if (system == null) { system = await repo.CreateSystem(null, importer._conn); - await repo.AddAccount(system.Id, userId); + await repo.AddAccount(system.Id, userId, importer._conn); importer._result.CreatedSystem = system.Hid; importer._system = system; }