Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V3: Start moderation refactor, add scoped session concept #1039

Merged
merged 2 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/Modix.Bot/Behaviors/ModerationLoggingBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public ModerationLoggingBehavior(
DesignatedChannelService = designatedChannelService;
Config = config.Value;

_lazyModerationService = new Lazy<IModerationService>(() => serviceProvider.GetRequiredService<IModerationService>());
_lazyModerationService = new Lazy<ModerationService>(() => serviceProvider.GetRequiredService<ModerationService>());
}

/// <inheritdoc />
Expand Down Expand Up @@ -95,9 +95,9 @@ public async Task OnModerationActionCreatedAsync(long moderationActionId, Modera
/// <summary>
/// An <see cref="IModerationService"/> for performing moderation actions.
/// </summary>
internal protected IModerationService ModerationService
internal protected ModerationService ModerationService
=> _lazyModerationService.Value;
private readonly Lazy<IModerationService> _lazyModerationService;
private readonly Lazy<ModerationService> _lazyModerationService;

internal protected static ModixConfig Config { get; private set; }

Expand Down
40 changes: 40 additions & 0 deletions src/Modix.Bot/DiscordBotSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
using Modix.Data.Models.Core;
using Modix.Services;

namespace Modix.Bot;

public class DiscordBotSession(DiscordSocketClient discordSocketClient,
AuthorizationClaimService authorizationClaimService) : IScopedSession
{
public ulong SelfUserId { get; } = discordSocketClient.CurrentUser.Id;

private ulong _executingUserId;

public ulong ExecutingUserId =>
_executingUserId == default
? SelfUserId
: _executingUserId;

private IReadOnlyCollection<AuthorizationClaim> _authorizationClaims;

public void ApplyCommandContext(ICommandContext context)
{
_executingUserId = context.User.Id;
}

private async Task<IReadOnlyCollection<AuthorizationClaim>> GetClaims()
{
return _authorizationClaims ??= await authorizationClaimService.GetClaimsForUser(ExecutingUserId);
}

public async Task<bool> HasClaim(params AuthorizationClaim[] claims)
{
var ownedClaims = await GetClaims();
return claims.All(claim => ownedClaims.Contains(claim));
}
}
97 changes: 63 additions & 34 deletions src/Modix.Bot/ModixBot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Microsoft.Extensions.Options;
using Modix.Bot.Notifications;
using Modix.Data.Models.Core;
using Modix.Services;

namespace Modix.Bot
{
Expand Down Expand Up @@ -61,6 +62,12 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
discordSocketClient.MessageDeleted += OnMessageDeleted;
discordSocketClient.ReactionAdded += OnReactionAdded;
discordSocketClient.ReactionRemoved += OnReactionRemoved;
discordSocketClient.UserJoined += OnUserJoined;
discordSocketClient.AuditLogCreated += OnAuditLogCreated;
discordSocketClient.GuildAvailable += OnGuildAvailable;
discordSocketClient.ChannelCreated += OnChannelCreated;
discordSocketClient.ChannelUpdated += OnChannelUpdated;
discordSocketClient.JoinedGuild += OnJoinedGuild;

discordRestClient.Log += discordSerilogAdapter.HandleLog;
commandService.Log += discordSerilogAdapter.HandleLog;
Expand All @@ -77,7 +84,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
await commandService.AddModulesAsync(typeof(ModixBot).Assembly, _scope.ServiceProvider);

logger.LogInformation("{Modules} modules loaded, containing {Commands} commands",
commandService.Modules.Count(), commandService.Modules.SelectMany(d=>d.Commands).Count());
commandService.Modules.Count(), commandService.Modules.SelectMany(d => d.Commands).Count());

logger.LogInformation("Logging into Discord and starting the client");

Expand All @@ -87,18 +94,24 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)

logger.LogInformation("Loading interaction modules...");

var modules = (await interactionService.AddModulesAsync(typeof(ModixBot).Assembly, _scope.ServiceProvider)).ToArray();
var modules =
(await interactionService.AddModulesAsync(typeof(ModixBot).Assembly, _scope.ServiceProvider))
.ToArray();

foreach (var guild in discordSocketClient.Guilds)
{
var commands = await interactionService.AddModulesToGuildAsync(guild, deleteMissing: true, modules);
}

logger.LogInformation("{Modules} interaction modules loaded", modules.Length);
logger.LogInformation("Loaded {SlashCommands} slash commands", modules.SelectMany(x => x.SlashCommands).Count());
logger.LogInformation("Loaded {ContextCommands} context commands", modules.SelectMany(x => x.ContextCommands).Count());
logger.LogInformation("Loaded {ModalCommands} modal commands", modules.SelectMany(x => x.ModalCommands).Count());
logger.LogInformation("Loaded {ComponentCommands} component commands", modules.SelectMany(x => x.ComponentCommands).Count());
logger.LogInformation("Loaded {SlashCommands} slash commands",
modules.SelectMany(x => x.SlashCommands).Count());
logger.LogInformation("Loaded {ContextCommands} context commands",
modules.SelectMany(x => x.ContextCommands).Count());
logger.LogInformation("Loaded {ModalCommands} modal commands",
modules.SelectMany(x => x.ModalCommands).Count());
logger.LogInformation("Loaded {ComponentCommands} component commands",
modules.SelectMany(x => x.ComponentCommands).Count());

await Task.Delay(-1, stoppingToken);
}
Expand Down Expand Up @@ -154,7 +167,7 @@ private Task OnDisconnect(Exception ex)
{
// Reconnections are handled by Discord.NET, we
// don't need to worry about handling this ourselves
if(ex is GatewayReconnectException)
if (ex is GatewayReconnectException)
{
logger.LogInformation("Received gateway reconnect");
return Task.CompletedTask;
Expand All @@ -171,7 +184,6 @@ private async Task StartClient(CancellationToken cancellationToken)

try
{

cancellationToken.ThrowIfCancellationRequested();

await discordSocketClient.LoginAsync(TokenType.Bot, modixConfig.Value.DiscordToken);
Expand All @@ -193,14 +205,18 @@ private void UnregisterClientHandlers()
discordSocketClient.LatencyUpdated -= OnLatencyUpdated;
discordSocketClient.Disconnected -= OnDisconnect;
discordSocketClient.Log -= discordSerilogAdapter.HandleLog;

discordSocketClient.Ready -= OnClientReady;

discordSocketClient.MessageReceived -= OnMessageReceived;
discordSocketClient.MessageUpdated -= OnMessageUpdated;
discordSocketClient.MessageDeleted -= OnMessageDeleted;
discordSocketClient.ReactionAdded -= OnReactionAdded;
discordSocketClient.ReactionRemoved -= OnReactionRemoved;
discordSocketClient.UserJoined -= OnUserJoined;
discordSocketClient.AuditLogCreated -= OnAuditLogCreated;
discordSocketClient.GuildAvailable -= OnGuildAvailable;
discordSocketClient.ChannelCreated -= OnChannelCreated;
discordSocketClient.ChannelUpdated -= OnChannelUpdated;
discordSocketClient.JoinedGuild -= OnJoinedGuild;
}

private async Task OnClientReady()
Expand All @@ -209,40 +225,53 @@ private async Task OnClientReady()
_whenReadySource.SetResult(null);
}

private async Task OnMessageReceived(SocketMessage arg)
private async Task PublishMessage<T>(T message) where T : INotification
{
using var scope = serviceProvider.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
await mediator.Publish(new MessageReceivedNotificationV3(arg));
await PublishMessage(scope, message);
}

private async Task OnMessageUpdated(Cacheable<IMessage, ulong> cachedMessage, SocketMessage newMessage, ISocketMessageChannel channel)
private async Task PublishMessage<T>(IServiceScope scope, T message) where T : INotification
{
using var scope = serviceProvider.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
await mediator.Publish(new MessageUpdatedNotificationV3(cachedMessage, newMessage, channel));
await mediator.Publish(message);
}

private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> channel)
{
using var scope = serviceProvider.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
await mediator.Publish(new MessageDeletedNotificationV3(message, channel));
}
private Task OnMessageReceived(SocketMessage message) =>
PublishMessage(new MessageReceivedNotificationV3(message));

private async Task OnReactionAdded(Cacheable<IUserMessage, ulong> message, Cacheable<IMessageChannel, ulong> channel, SocketReaction reaction)
{
using var scope = serviceProvider.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
await mediator.Publish(new ReactionAddedNotificationV3(message, channel, reaction));
}
private Task OnMessageUpdated(Cacheable<IMessage, ulong> cachedMessage, SocketMessage newMessage,
ISocketMessageChannel channel) =>
PublishMessage(new MessageUpdatedNotificationV3(cachedMessage, newMessage, channel));

private async Task OnReactionRemoved(Cacheable<IUserMessage, ulong> message, Cacheable<IMessageChannel, ulong> channel, SocketReaction reaction)
{
using var scope = serviceProvider.CreateScope();
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
await mediator.Publish(new ReactionRemovedNotificationV3(message, channel, reaction));
}
private Task OnMessageDeleted(Cacheable<IMessage, ulong> message,
Cacheable<IMessageChannel, ulong> channel) =>
PublishMessage(new MessageDeletedNotificationV3(message, channel));

private Task OnReactionAdded(Cacheable<IUserMessage, ulong> message,
Cacheable<IMessageChannel, ulong> channel, SocketReaction reaction) =>
PublishMessage(new ReactionAddedNotificationV3(message, channel, reaction));

private Task OnReactionRemoved(Cacheable<IUserMessage, ulong> message,
Cacheable<IMessageChannel, ulong> channel, SocketReaction reaction) =>
PublishMessage(new ReactionRemovedNotificationV3(message, channel, reaction));

private Task OnUserJoined(SocketGuildUser guildUser) =>
PublishMessage(new UserJoinedNotificationV3(guildUser));

private Task OnAuditLogCreated(SocketAuditLogEntry entry, SocketGuild guild) =>
PublishMessage(new AuditLogCreatedNotificationV3(entry, guild));

private Task OnGuildAvailable(SocketGuild guild)
=> PublishMessage(new GuildAvailableNotificationV3(guild));

private Task OnChannelCreated(SocketChannel channel) =>
PublishMessage(new ChannelCreatedNotificationV3(channel));

private Task OnChannelUpdated(SocketChannel oldChannel, SocketChannel newChannel) =>
PublishMessage(new ChannelUpdatedNotificationV3(oldChannel, newChannel));

private Task OnJoinedGuild(SocketGuild guild) => PublishMessage(new JoinedGuildNotificationV3(guild));

public override void Dispose()
{
Expand Down
4 changes: 2 additions & 2 deletions src/Modix.Bot/Modules/InfractionModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ namespace Modix.Modules
[ModuleHelp("Infractions", "Provides commands for working with infractions.")]
public class InfractionModule : InteractionModuleBase
{
private readonly IModerationService _moderationService;
private readonly ModerationService _moderationService;
private readonly ModixConfig _config;

public InfractionModule(IModerationService moderationService, IOptions<ModixConfig> config)
public InfractionModule(ModerationService moderationService, IOptions<ModixConfig> config)
{
_moderationService = moderationService;
_config = config.Value;
Expand Down
4 changes: 2 additions & 2 deletions src/Modix.Bot/Modules/ModerationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace Modix.Modules
public class ModerationModule : ModuleBase
{
public ModerationModule(
IModerationService moderationService,
ModerationService moderationService,
IUserService userService,
IOptions<ModixConfig> config)
{
Expand Down Expand Up @@ -306,7 +306,7 @@ private async ValueTask<bool> GetConfirmationIfRequiredAsync(DiscordUserOrMessag
+ $"{Format.Bold(author.GetDisplayName())} ({userOrAuthor.UserId}), the message's author?");
}

internal protected IModerationService ModerationService { get; }
internal protected ModerationService ModerationService { get; }

internal protected IUserService UserService { get; }

Expand Down
4 changes: 2 additions & 2 deletions src/Modix.Bot/Modules/UserInfoModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class UserInfoModule : InteractionModuleBase
{
private readonly ILogger<UserInfoModule> _log;
private readonly IUserService _userService;
private readonly IModerationService _moderationService;
private readonly ModerationService _moderationService;
private readonly IAuthorizationService _authorizationService;
private readonly IMessageRepository _messageRepository;
private readonly IEmojiRepository _emojiRepository;
Expand All @@ -51,7 +51,7 @@ public class UserInfoModule : InteractionModuleBase
public UserInfoModule(
ILogger<UserInfoModule> logger,
IUserService userService,
IModerationService moderationService,
ModerationService moderationService,
IAuthorizationService authorizationService,
IMessageRepository messageRepository,
IEmojiRepository emojiRepository,
Expand Down
10 changes: 10 additions & 0 deletions src/Modix.Bot/Notifications/AuditLogCreatedNotificationV3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Discord.WebSocket;
using MediatR;

namespace Modix.Bot.Notifications;

public class AuditLogCreatedNotificationV3(SocketAuditLogEntry entry, SocketGuild guild) : INotification
{
public SocketAuditLogEntry Entry { get; } = entry;
public SocketGuild Guild { get; } = guild;
}
9 changes: 9 additions & 0 deletions src/Modix.Bot/Notifications/ChannelCreatedNotificationV3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Discord.WebSocket;
using MediatR;

namespace Modix.Bot.Notifications;

public class ChannelCreatedNotificationV3(SocketChannel channel) : INotification
{
public SocketChannel Channel { get; } = channel;
}
10 changes: 10 additions & 0 deletions src/Modix.Bot/Notifications/ChannelUpdatedNotificationV3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Discord.WebSocket;
using MediatR;

namespace Modix.Bot.Notifications;

public class ChannelUpdatedNotificationV3(SocketChannel oldChannel, SocketChannel newChannel) : INotification
{
public SocketChannel OldChannel { get; } = oldChannel;
public SocketChannel NewChannel { get; } = newChannel;
}
9 changes: 9 additions & 0 deletions src/Modix.Bot/Notifications/GuildAvailableNotificationV3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Discord.WebSocket;
using MediatR;

namespace Modix.Bot.Notifications;

public class GuildAvailableNotificationV3(SocketGuild guild) : INotification
{
public SocketGuild Guild { get; } = guild;
}
9 changes: 9 additions & 0 deletions src/Modix.Bot/Notifications/JoinedGuildNotificationV3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Discord.WebSocket;
using MediatR;

namespace Modix.Bot.Notifications;

public class JoinedGuildNotificationV3(SocketGuild guild) : INotification
{
public SocketGuild Guild { get; } = guild;
}
9 changes: 9 additions & 0 deletions src/Modix.Bot/Notifications/UserJoinedNotificationV3.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Discord.WebSocket;
using MediatR;

namespace Modix.Bot.Notifications;

public class UserJoinedNotificationV3(SocketGuildUser guildUser) : INotification
{
public SocketGuildUser GuildUser { get; } = guildUser;
}
Loading
Loading