feat: watchlist repository, remove ef core from all bot code

This commit is contained in:
sam 2024-10-28 02:14:41 +01:00
parent da4dfae27c
commit f0511a560c
Signed by: sam
GPG key ID: 5F3C3C1B3166639D
19 changed files with 155 additions and 97 deletions

View file

@ -19,6 +19,7 @@ using Catalogger.Backend.Bot;
using Catalogger.Backend.Database.Queries; using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services; using Catalogger.Backend.Services;
using Dapper;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Embeds;
@ -40,7 +41,7 @@ public partial class GuildsController
); );
} }
var guildConfig = await db.GetGuildAsync(guildId.Value, false); var guildConfig = await guildRepository.GetAsync(guildId);
var logChannelId = var logChannelId =
webhookExecutor.GetLogChannel(guildConfig, LogChannelType.GuildUpdate) webhookExecutor.GetLogChannel(guildConfig, LogChannelType.GuildUpdate)
?? webhookExecutor.GetLogChannel(guildConfig, LogChannelType.GuildMemberRemove); ?? webhookExecutor.GetLogChannel(guildConfig, LogChannelType.GuildMemberRemove);
@ -80,17 +81,32 @@ public partial class GuildsController
); );
} }
await using var tx = await db.Database.BeginTransactionAsync(); await using var tx = await dbConn.BeginTransactionAsync();
var inviteCount = await db
.Invites.Where(i => i.GuildId == guildId.Value) var inviteCount = await dbConn.ExecuteAsync(
.ExecuteDeleteAsync(); "delete from invites where guild_id = @GuildId",
var watchlistCount = await db new { GuildId = guildId.Value },
.Watchlists.Where(w => w.GuildId == guildId.Value) tx
.ExecuteDeleteAsync(); );
var messageCount = await db
.Messages.Where(m => m.GuildId == guildId.Value) var watchlistCount = await dbConn.ExecuteAsync(
.ExecuteDeleteAsync(); "delete from watchlists where guild_id = @GuildId",
await db.Guilds.Where(g => g.Id == guildId.Value).ExecuteDeleteAsync(); new { GuildId = guildId.Value },
tx
);
var messageCount = await dbConn.ExecuteAsync(
"delete from messages where guild_id = @GuildId",
new { GuildId = guildId.Value },
tx
);
await dbConn.ExecuteAsync(
"delete from guilds where id = @GuildId",
new { GuildId = guildId.Value },
tx
);
await tx.CommitAsync(); await tx.CommitAsync();
_logger.Information( _logger.Information(

View file

@ -18,8 +18,8 @@ using Catalogger.Backend.Api.Middleware;
using Catalogger.Backend.Cache; using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database; using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Queries; using Catalogger.Backend.Database.Dapper;
using Catalogger.Backend.Database.Redis; using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Services; using Catalogger.Backend.Services;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Remora.Discord.API; using Remora.Discord.API;
@ -33,6 +33,8 @@ namespace Catalogger.Backend.Api;
public partial class GuildsController( public partial class GuildsController(
ILogger logger, ILogger logger,
DatabaseContext db, DatabaseContext db,
DatabaseConnection dbConn,
GuildRepository guildRepository,
GuildCache guildCache, GuildCache guildCache,
EmojiCache emojiCache, EmojiCache emojiCache,
ChannelCache channelCache, ChannelCache channelCache,
@ -70,7 +72,7 @@ public partial class GuildsController(
{ {
var (guildId, guild) = await ParseGuildAsync(id); var (guildId, guild) = await ParseGuildAsync(id);
var guildConfig = await db.GetGuildAsync(guildId.Value, false); var guildConfig = await guildRepository.GetAsync(guildId);
var channels = channelCache var channels = channelCache
.GuildChannels(guildId) .GuildChannels(guildId)
@ -134,12 +136,12 @@ public partial class GuildsController(
[ProducesResponseType<Database.Models.Guild.ChannelConfig>(statusCode: StatusCodes.Status200OK)] [ProducesResponseType<Database.Models.Guild.ChannelConfig>(statusCode: StatusCodes.Status200OK)]
public async Task<IActionResult> PatchGuildAsync(string id, [FromBody] ChannelRequest req) public async Task<IActionResult> PatchGuildAsync(string id, [FromBody] ChannelRequest req)
{ {
var (guildId, guild) = await ParseGuildAsync(id); var (guildId, _) = await ParseGuildAsync(id);
var guildChannels = channelCache var guildChannels = channelCache
.GuildChannels(guildId) .GuildChannels(guildId)
.Where(c => c.Type is ChannelType.GuildText) .Where(c => c.Type is ChannelType.GuildText)
.ToList(); .ToList();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
if (req.IgnoredChannels != null) if (req.IgnoredChannels != null)
{ {
@ -316,9 +318,7 @@ public partial class GuildsController(
) )
guildConfig.Channels.MessageDeleteBulk = req.MessageDeleteBulk ?? 0; guildConfig.Channels.MessageDeleteBulk = req.MessageDeleteBulk ?? 0;
db.Update(guildConfig); await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels);
await db.SaveChangesAsync();
return Ok(guildConfig.Channels); return Ok(guildConfig.Channels);
} }

View file

@ -17,6 +17,7 @@ using System.ComponentModel;
using Catalogger.Backend.Cache; using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database; using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Database.Queries; using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services; using Catalogger.Backend.Services;
@ -42,7 +43,7 @@ namespace Catalogger.Backend.Bot.Commands;
public class ChannelCommands( public class ChannelCommands(
ILogger logger, ILogger logger,
Config config, Config config,
DatabaseContext db, GuildRepository guildRepository,
GuildCache guildCache, GuildCache guildCache,
ChannelCache channelCache, ChannelCache channelCache,
IMemberCache memberCache, IMemberCache memberCache,
@ -207,7 +208,7 @@ public class ChannelCommands(
if (!guildCache.TryGet(guildId, out var guild)) if (!guildCache.TryGet(guildId, out var guild))
throw new CataloggerError("Guild not in cache"); throw new CataloggerError("Guild not in cache");
var guildChannels = channelCache.GuildChannels(guildId).ToList(); var guildChannels = channelCache.GuildChannels(guildId).ToList();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
var (embeds, components) = BuildRootMenu(guildChannels, guild, guildConfig); var (embeds, components) = BuildRootMenu(guildChannels, guild, guildConfig);

View file

@ -14,8 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database; using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services; using Catalogger.Backend.Services;
using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Objects;
@ -24,7 +23,6 @@ using Remora.Discord.API.Objects;
using Remora.Discord.Commands.Attributes; using Remora.Discord.Commands.Attributes;
using Remora.Discord.Commands.Contexts; using Remora.Discord.Commands.Contexts;
using Remora.Discord.Commands.Extensions; using Remora.Discord.Commands.Extensions;
using Remora.Discord.Commands.Feedback.Messages;
using Remora.Discord.Commands.Feedback.Services; using Remora.Discord.Commands.Feedback.Services;
using Remora.Discord.Commands.Services; using Remora.Discord.Commands.Services;
using Remora.Discord.Interactivity; using Remora.Discord.Interactivity;
@ -36,7 +34,7 @@ namespace Catalogger.Backend.Bot.Commands;
public class ChannelCommandsComponents( public class ChannelCommandsComponents(
ILogger logger, ILogger logger,
DatabaseContext db, GuildRepository guildRepository,
GuildCache guildCache, GuildCache guildCache,
ChannelCache channelCache, ChannelCache channelCache,
ContextInjectionService contextInjection, ContextInjectionService contextInjection,
@ -62,7 +60,7 @@ public class ChannelCommandsComponents(
if (!guildCache.TryGet(guildId, out var guild)) if (!guildCache.TryGet(guildId, out var guild))
throw new CataloggerError("Guild not in cache"); throw new CataloggerError("Guild not in cache");
var guildChannels = channelCache.GuildChannels(guildId).ToList(); var guildChannels = channelCache.GuildChannels(guildId).ToList();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
var result = await dataService.LeaseDataAsync(msg.ID); var result = await dataService.LeaseDataAsync(msg.ID);
await using var lease = result.GetOrThrow(); await using var lease = result.GetOrThrow();
@ -166,8 +164,7 @@ public class ChannelCommandsComponents(
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
db.Update(guildConfig); await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels);
await db.SaveChangesAsync();
goto case "return"; goto case "return";
case "return": case "return":
var (e, c) = ChannelCommands.BuildRootMenu(guildChannels, guild, guildConfig); var (e, c) = ChannelCommands.BuildRootMenu(guildChannels, guild, guildConfig);
@ -260,7 +257,7 @@ public class ChannelCommandsComponents(
throw new CataloggerError("No guild ID in context"); throw new CataloggerError("No guild ID in context");
if (!guildCache.TryGet(guildId, out var guild)) if (!guildCache.TryGet(guildId, out var guild))
throw new CataloggerError("Guild not in cache"); throw new CataloggerError("Guild not in cache");
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
var channelId = channels[0].ID.ToUlong(); var channelId = channels[0].ID.ToUlong();
var result = await dataService.LeaseDataAsync(msg.ID); var result = await dataService.LeaseDataAsync(msg.ID);
@ -354,8 +351,7 @@ public class ChannelCommandsComponents(
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
db.Update(guildConfig); await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels);
await db.SaveChangesAsync();
List<IEmbed> embeds = List<IEmbed> embeds =
[ [

View file

@ -16,8 +16,7 @@
using System.ComponentModel; using System.ComponentModel;
using Catalogger.Backend.Cache; using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database; using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services; using Catalogger.Backend.Services;
using Remora.Commands.Attributes; using Remora.Commands.Attributes;
@ -38,7 +37,7 @@ namespace Catalogger.Backend.Bot.Commands;
[DiscordDefaultMemberPermissions(DiscordPermission.ManageGuild)] [DiscordDefaultMemberPermissions(DiscordPermission.ManageGuild)]
public class IgnoreChannelCommands( public class IgnoreChannelCommands(
ILogger logger, ILogger logger,
DatabaseContext db, GuildRepository guildRepository,
IMemberCache memberCache, IMemberCache memberCache,
GuildCache guildCache, GuildCache guildCache,
ChannelCache channelCache, ChannelCache channelCache,
@ -66,7 +65,7 @@ public class IgnoreChannelCommands(
) )
{ {
var (_, guildId) = contextInjection.GetUserAndGuild(); var (_, guildId) = contextInjection.GetUserAndGuild();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
if (guildConfig.Channels.IgnoredChannels.Contains(channel.ID.Value)) if (guildConfig.Channels.IgnoredChannels.Contains(channel.ID.Value))
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
@ -75,8 +74,7 @@ public class IgnoreChannelCommands(
); );
guildConfig.Channels.IgnoredChannels.Add(channel.ID.Value); guildConfig.Channels.IgnoredChannels.Add(channel.ID.Value);
db.Update(guildConfig); await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels);
await db.SaveChangesAsync();
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
$"Successfully added {(channel.Type == ChannelType.GuildCategory ? channel.Name : $"<#{channel.ID}>")} to the list of ignored channels." $"Successfully added {(channel.Type == ChannelType.GuildCategory ? channel.Name : $"<#{channel.ID}>")} to the list of ignored channels."
@ -90,7 +88,7 @@ public class IgnoreChannelCommands(
) )
{ {
var (_, guildId) = contextInjection.GetUserAndGuild(); var (_, guildId) = contextInjection.GetUserAndGuild();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
if (!guildConfig.Channels.IgnoredChannels.Contains(channel.ID.Value)) if (!guildConfig.Channels.IgnoredChannels.Contains(channel.ID.Value))
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
@ -99,8 +97,7 @@ public class IgnoreChannelCommands(
); );
guildConfig.Channels.IgnoredChannels.Remove(channel.ID.Value); guildConfig.Channels.IgnoredChannels.Remove(channel.ID.Value);
db.Update(guildConfig); await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels);
await db.SaveChangesAsync();
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
$"Successfully removed {(channel.Type == ChannelType.GuildCategory ? channel.Name : $"<#{channel.ID}>")} from the list of ignored channels." $"Successfully removed {(channel.Type == ChannelType.GuildCategory ? channel.Name : $"<#{channel.ID}>")} from the list of ignored channels."
@ -116,7 +113,7 @@ public class IgnoreChannelCommands(
throw new CataloggerError("Guild not in cache"); throw new CataloggerError("Guild not in cache");
var guildChannels = channelCache.GuildChannels(guildId).ToList(); var guildChannels = channelCache.GuildChannels(guildId).ToList();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
var member = await memberCache.TryGetAsync(guildId, userId); var member = await memberCache.TryGetAsync(guildId, userId);
if (member == null) if (member == null)

View file

@ -15,8 +15,7 @@
using System.ComponentModel; using System.ComponentModel;
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database; using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Remora.Commands.Attributes; using Remora.Commands.Attributes;
using Remora.Commands.Groups; using Remora.Commands.Groups;
@ -33,7 +32,7 @@ namespace Catalogger.Backend.Bot.Commands;
[Group("key-roles")] [Group("key-roles")]
[DiscordDefaultMemberPermissions(DiscordPermission.ManageGuild)] [DiscordDefaultMemberPermissions(DiscordPermission.ManageGuild)]
public class KeyRoleCommands( public class KeyRoleCommands(
DatabaseContext db, GuildRepository guildRepository,
ContextInjectionService contextInjection, ContextInjectionService contextInjection,
IFeedbackService feedbackService, IFeedbackService feedbackService,
GuildCache guildCache, GuildCache guildCache,
@ -48,7 +47,7 @@ public class KeyRoleCommands(
if (!guildCache.TryGet(guildId, out var guild)) if (!guildCache.TryGet(guildId, out var guild))
throw new CataloggerError("Guild not in cache"); throw new CataloggerError("Guild not in cache");
var guildRoles = roleCache.GuildRoles(guildId).ToList(); var guildRoles = roleCache.GuildRoles(guildId).ToList();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
if (guildConfig.KeyRoles.Length == 0) if (guildConfig.KeyRoles.Length == 0)
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
@ -85,17 +84,14 @@ public class KeyRoleCommands(
if (role == null) if (role == null)
throw new CataloggerError("Role is not cached"); throw new CataloggerError("Role is not cached");
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
if (guildConfig.KeyRoles.Any(id => role.ID == id)) if (guildConfig.KeyRoles.Any(id => role.ID.Value == id))
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
$"{role.Name} is already a key role.", $"{role.Name} is already a key role.",
isEphemeral: true isEphemeral: true
); );
guildConfig.KeyRoles = guildConfig.KeyRoles.Append(role.ID.Value).ToArray(); await guildRepository.AddKeyRoleAsync(guildId, role.ID);
db.Update(guildConfig);
await db.SaveChangesAsync();
return await feedbackService.ReplyAsync($"Added {role.Name} to this server's key roles!"); return await feedbackService.ReplyAsync($"Added {role.Name} to this server's key roles!");
} }
@ -110,17 +106,14 @@ public class KeyRoleCommands(
if (role == null) if (role == null)
throw new CataloggerError("Role is not cached"); throw new CataloggerError("Role is not cached");
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
if (guildConfig.KeyRoles.All(id => role.ID != id)) if (guildConfig.KeyRoles.All(id => role.ID != id))
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
$"{role.Name} is already not a key role.", $"{role.Name} is already not a key role.",
isEphemeral: true isEphemeral: true
); );
guildConfig.KeyRoles = guildConfig.KeyRoles.Except([role.ID.Value]).ToArray(); await guildRepository.RemoveKeyRoleAsync(guildId, role.ID);
db.Update(guildConfig);
await db.SaveChangesAsync();
return await feedbackService.ReplyAsync( return await feedbackService.ReplyAsync(
$"Removed {role.Name} from this server's key roles!" $"Removed {role.Name} from this server's key roles!"
); );

View file

@ -15,8 +15,7 @@
using System.ComponentModel; using System.ComponentModel;
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database; using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Remora.Commands.Attributes; using Remora.Commands.Attributes;
using Remora.Commands.Groups; using Remora.Commands.Groups;
@ -34,7 +33,7 @@ namespace Catalogger.Backend.Bot.Commands;
[Description("Commands for configuring log redirects.")] [Description("Commands for configuring log redirects.")]
[DiscordDefaultMemberPermissions(DiscordPermission.ManageGuild)] [DiscordDefaultMemberPermissions(DiscordPermission.ManageGuild)]
public class RedirectCommands( public class RedirectCommands(
DatabaseContext db, GuildRepository guildRepository,
GuildCache guildCache, GuildCache guildCache,
ChannelCache channelCache, ChannelCache channelCache,
ContextInjectionService contextInjectionService, ContextInjectionService contextInjectionService,
@ -60,10 +59,9 @@ public class RedirectCommands(
) )
{ {
var (_, guildId) = contextInjectionService.GetUserAndGuild(); var (_, guildId) = contextInjectionService.GetUserAndGuild();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
guildConfig.Channels.Redirects[source.ID.Value] = target.ID.Value; guildConfig.Channels.Redirects[source.ID.Value] = target.ID.Value;
db.Update(guildConfig); await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels);
await db.SaveChangesAsync();
var output = var output =
$"Success! Edited and deleted messages from {FormatChannel(source)} will now be redirected to <#{target.ID}>."; $"Success! Edited and deleted messages from {FormatChannel(source)} will now be redirected to <#{target.ID}>.";
@ -100,9 +98,11 @@ public class RedirectCommands(
) )
{ {
var (_, guildId) = contextInjectionService.GetUserAndGuild(); var (_, guildId) = contextInjectionService.GetUserAndGuild();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
var wasSet = guildConfig.Channels.Redirects.Remove(source.ID.Value); var wasSet = guildConfig.Channels.Redirects.Remove(source.ID.Value);
await guildRepository.UpdateChannelConfigAsync(guildId, guildConfig.Channels);
var output = wasSet var output = wasSet
? $"Removed the redirect for {FormatChannel(source)}! Message logs from" ? $"Removed the redirect for {FormatChannel(source)}! Message logs from"
+ $"{(source.Type == ChannelType.GuildCategory ? "that category's channels" : "that channel")}" + $"{(source.Type == ChannelType.GuildCategory ? "that category's channels" : "that channel")}"
@ -132,9 +132,6 @@ public class RedirectCommands(
$"\nHowever, all channels in the {parentChannelName} category are being redirected to <#{parentRedirect}>."; $"\nHowever, all channels in the {parentChannelName} category are being redirected to <#{parentRedirect}>.";
} }
db.Update(guildConfig);
await db.SaveChangesAsync();
return await feedbackService.ReplyAsync(output); return await feedbackService.ReplyAsync(output);
} }
@ -146,7 +143,7 @@ public class RedirectCommands(
if (!guildCache.TryGet(guildId, out var guild)) if (!guildCache.TryGet(guildId, out var guild))
throw new CataloggerError("Guild was not cached"); throw new CataloggerError("Guild was not cached");
var guildChannels = channelCache.GuildChannels(guildId).ToList(); var guildChannels = channelCache.GuildChannels(guildId).ToList();
var guildConfig = await db.GetGuildAsync(guildId); var guildConfig = await guildRepository.GetAsync(guildId);
var fields = new List<IEmbedField>(); var fields = new List<IEmbedField>();

View file

@ -14,13 +14,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
using Catalogger.Backend.Cache; using Catalogger.Backend.Cache;
using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Dapper;
using Catalogger.Backend.Database.Dapper.Repositories; using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services; using Catalogger.Backend.Services;
using Microsoft.EntityFrameworkCore;
using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Gateway.Events;
using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.API.Abstractions.Rest;
using Remora.Discord.Extensions.Embeds; using Remora.Discord.Extensions.Embeds;

View file

@ -15,13 +15,10 @@
using Catalogger.Backend.Cache; using Catalogger.Backend.Cache;
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Dapper.Repositories; using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services; using Catalogger.Backend.Services;
using Humanizer; using Humanizer;
using Microsoft.EntityFrameworkCore;
using Remora.Discord.API; using Remora.Discord.API;
using Remora.Discord.API.Abstractions.Gateway.Events; using Remora.Discord.API.Abstractions.Gateway.Events;
using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Objects;
@ -35,9 +32,9 @@ namespace Catalogger.Backend.Bot.Responders.Members;
public class GuildMemberAddResponder( public class GuildMemberAddResponder(
ILogger logger, ILogger logger,
DatabaseContext db,
InviteRepository inviteRepository, InviteRepository inviteRepository,
GuildRepository guildRepository, GuildRepository guildRepository,
WatchlistRepository watchlistRepository,
IMemberCache memberCache, IMemberCache memberCache,
IInviteCache inviteCache, IInviteCache inviteCache,
UserCache userCache, UserCache userCache,
@ -159,7 +156,7 @@ public class GuildMemberAddResponder(
); );
} }
var watchlist = await db.GetWatchlistEntryAsync(member.GuildID, user.ID, ct); var watchlist = await watchlistRepository.GetWatchlistEntryAsync(member.GuildID, user.ID);
if (watchlist != null) if (watchlist != null)
{ {
var moderator = await userCache.GetUserAsync( var moderator = await userCache.GetUserAsync(

View file

@ -14,9 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Dapper.Repositories; using Catalogger.Backend.Database.Dapper.Repositories;
using Catalogger.Backend.Database.Queries;
using Catalogger.Backend.Extensions; using Catalogger.Backend.Extensions;
using Catalogger.Backend.Services; using Catalogger.Backend.Services;
using Remora.Discord.API; using Remora.Discord.API;
@ -32,7 +30,7 @@ namespace Catalogger.Backend.Bot.Responders.Messages;
public class MessageUpdateResponder( public class MessageUpdateResponder(
ILogger logger, ILogger logger,
DatabaseContext db, GuildRepository guildRepository,
ChannelCache channelCache, ChannelCache channelCache,
UserCache userCache, UserCache userCache,
MessageRepository messageRepository, MessageRepository messageRepository,
@ -57,7 +55,7 @@ public class MessageUpdateResponder(
return Result.Success; return Result.Success;
} }
var guildConfig = await db.GetGuildAsync(msg.GuildID.Value, false, ct); var guildConfig = await guildRepository.GetAsync(msg.GuildID);
if (await messageRepository.IsMessageIgnoredAsync(msg.ID.Value)) if (await messageRepository.IsMessageIgnoredAsync(msg.ID.Value))
{ {

View file

@ -43,7 +43,7 @@ public class DatabaseConnection(Guid id, ILogger logger, NpgsqlConnection inner)
DatabasePool.DecrementConnections(); DatabasePool.DecrementConnections();
var openFor = DateTimeOffset.UtcNow - _openTime; var openFor = DateTimeOffset.UtcNow - _openTime;
_logger.Debug("Closing connection {ConnId}, open for {OpenFor}", ConnectionId, openFor); _logger.Verbose("Closing connection {ConnId}, open for {OpenFor}", ConnectionId, openFor);
_hasClosed = true; _hasClosed = true;
await inner.CloseAsync(); await inner.CloseAsync();
} }
@ -53,7 +53,7 @@ public class DatabaseConnection(Guid id, ILogger logger, NpgsqlConnection inner)
CancellationToken cancellationToken CancellationToken cancellationToken
) )
{ {
_logger.Debug("Beginning transaction on connection {ConnId}", ConnectionId); _logger.Verbose("Beginning transaction on connection {ConnId}", ConnectionId);
return await inner.BeginTransactionAsync(isolationLevel, cancellationToken); return await inner.BeginTransactionAsync(isolationLevel, cancellationToken);
} }

View file

@ -67,7 +67,7 @@ public class DatabasePool
private Guid LogOpen() private Guid LogOpen()
{ {
var connId = Guid.NewGuid(); var connId = Guid.NewGuid();
_logger.Debug("Opening database connection {ConnId}", connId); _logger.Verbose("Opening database connection {ConnId}", connId);
IncrementConnections(); IncrementConnections();
return connId; return connId;
} }

View file

@ -75,6 +75,24 @@ public class GuildRepository(ILogger logger, DatabaseConnection conn)
} }
); );
public async Task AddKeyRoleAsync(Snowflake guildId, Snowflake roleId) =>
await conn.ExecuteAsync(
"update guilds set key_roles = array_append(key_roles, @RoleId) where id = @GuildId",
new { GuildId = guildId.Value, RoleId = roleId.Value }
);
public async Task RemoveKeyRoleAsync(Snowflake guildId, Snowflake roleId) =>
await conn.ExecuteAsync(
"update guilds set key_roles = array_remove(key_roles, @RoleId) where id = @GuildId",
new { GuildId = guildId.Value, RoleId = roleId.Value }
);
public async Task UpdateChannelConfigAsync(Snowflake id, Guild.ChannelConfig config) =>
await conn.ExecuteAsync(
"update guilds set channels = @Channels where id = @Id",
new { Id = id, Channels = config }
);
public void Dispose() public void Dispose()
{ {
conn.Dispose(); conn.Dispose();

View file

@ -0,0 +1,53 @@
// Copyright (C) 2021-present sam (starshines.gay)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
using Catalogger.Backend.Database.Models;
using Dapper;
using Remora.Rest.Core;
namespace Catalogger.Backend.Database.Dapper.Repositories;
public class WatchlistRepository(ILogger logger, DatabaseConnection conn)
: IDisposable,
IAsyncDisposable
{
private readonly ILogger _logger = logger.ForContext<WatchlistRepository>();
public async Task<List<Watchlist>> GetGuildWatchlistAsync(Snowflake guildId) =>
(
await conn.QueryAsync<Watchlist>(
"select * from watchlists where guild_id = @GuildId",
new { GuildId = guildId.Value }
)
).ToList();
public async Task<Watchlist?> GetWatchlistEntryAsync(Snowflake guildId, Snowflake userId) =>
await conn.QueryFirstOrDefaultAsync<Watchlist>(
"select * from watchlists where guild_id = @GuildId and user_id = @UserId",
new { GuildId = guildId.Value, UserId = userId.Value }
);
public void Dispose()
{
conn.Dispose();
GC.SuppressFinalize(this);
}
public async ValueTask DisposeAsync()
{
await conn.DisposeAsync();
GC.SuppressFinalize(this);
}
}

View file

@ -53,14 +53,4 @@ public static class QueryExtensions
throw new CataloggerError("Guild not found, was not initialized during guild create"); throw new CataloggerError("Guild not found, was not initialized during guild create");
return guild; return guild;
} }
public static async Task<Watchlist?> GetWatchlistEntryAsync(
this DatabaseContext db,
Snowflake guildId,
Snowflake userId,
CancellationToken ct = default
) =>
await db
.Watchlists.AsNoTracking()
.FirstOrDefaultAsync(w => w.GuildId == guildId.Value && w.UserId == userId.Value, ct);
} }

View file

@ -109,6 +109,7 @@ public static class StartupExtensions
.AddScoped<MessageRepository>() .AddScoped<MessageRepository>()
.AddScoped<GuildRepository>() .AddScoped<GuildRepository>()
.AddScoped<InviteRepository>() .AddScoped<InviteRepository>()
.AddScoped<WatchlistRepository>()
.AddSingleton<GuildCache>() .AddSingleton<GuildCache>()
.AddSingleton<RoleCache>() .AddSingleton<RoleCache>()
.AddSingleton<ChannelCache>() .AddSingleton<ChannelCache>()

View file

@ -16,6 +16,8 @@
using System.Diagnostics; using System.Diagnostics;
using Catalogger.Backend.Cache.InMemoryCache; using Catalogger.Backend.Cache.InMemoryCache;
using Catalogger.Backend.Database; using Catalogger.Backend.Database;
using Catalogger.Backend.Database.Dapper;
using Dapper;
using Humanizer; using Humanizer;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Prometheus; using Prometheus;
@ -39,8 +41,9 @@ public class MetricsCollectionService(
await using var scope = services.CreateAsyncScope(); await using var scope = services.CreateAsyncScope();
await using var db = scope.ServiceProvider.GetRequiredService<DatabaseContext>(); await using var db = scope.ServiceProvider.GetRequiredService<DatabaseContext>();
await using var conn = scope.ServiceProvider.GetRequiredService<DatabaseConnection>();
var messageCount = await db.Messages.CountAsync(ct); var messageCount = await conn.ExecuteScalarAsync<int>("select count(id) from messages");
CataloggerMetrics.GuildsCached.Set(guildCache.Size); CataloggerMetrics.GuildsCached.Set(guildCache.Size);
CataloggerMetrics.ChannelsCached.Set(channelCache.Size); CataloggerMetrics.ChannelsCached.Set(channelCache.Size);

View file

@ -61,6 +61,7 @@ public class WebhookExecutorService(
public void QueueLog(Guild guildConfig, LogChannelType logChannelType, IEmbed embed) public void QueueLog(Guild guildConfig, LogChannelType logChannelType, IEmbed embed)
{ {
var logChannel = GetLogChannel(guildConfig, logChannelType, channelId: null, userId: null); var logChannel = GetLogChannel(guildConfig, logChannelType, channelId: null, userId: null);
_logger.Debug("Channel to log {Type} to: {LogChannel}", logChannelType, logChannel);
if (logChannel == null) if (logChannel == null)
return; return;
@ -72,6 +73,7 @@ public class WebhookExecutorService(
/// </summary> /// </summary>
public void QueueLog(ulong channelId, IEmbed embed) public void QueueLog(ulong channelId, IEmbed embed)
{ {
_logger.Debug("Channel to log to: {LogChannel}", channelId);
if (channelId == 0) if (channelId == 0)
return; return;

View file

@ -93,8 +93,8 @@ public static class GuildImport
var dbGuild = new Guild var dbGuild = new Guild
{ {
Id = guild.Id, Id = guild.Id,
BannedSystems = guild.BannedSystems.ToList(), BannedSystems = guild.BannedSystems,
KeyRoles = guild.KeyRoles.ToList(), KeyRoles = guild.KeyRoles,
Channels = channels, Channels = channels,
}; };