1
0
Fork 1
mirror of https://github.com/TeamOctolings/Octobot.git synced 2025-05-05 21:46:28 +03:00

Split GuildUpdateService into separate services (#80)

GuildUpdateService is a service that contains way too many
responsibilities with everything strictly coupled to each other. The
code is buggy, hard to refactor and swallows errors. This prompted me to
make this PR, which splits it into three independant services:
- SongUpdateService (responsible for changing songs presence);
- MemberUpdateService (responsible for updating member datas: unbanning
users, adding the default role, sending reminders, filtering nicknames);
- ScheduledEventUpdateService (responsible for updating scheduled
events: sending notifications, automatically starting events).

All of these services and their methods use Results to push errors all
the way up in the stack, making sure no error is missed. To make logging
and debugging easier, an extension method for `ILogger` was created -
`LogResult`. The method checks if the result was successful or if its
failure was caused by a user or environment error before logging
anything - providing cleaner code and logs. `ExceptionError`s will also
have their exception stacktrace and type logged (except in Remora code).

This PR also fixes an issue that prevented banned users from being
unbanned when their punishment was over.

---------

Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
Octol1ttle 2023-08-05 23:02:40 +05:00 committed by GitHub
parent e9f7825e4a
commit f260681b39
Signed by: GitHub
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 720 additions and 653 deletions

View file

@ -2,6 +2,7 @@ using System.ComponentModel;
using System.Text;
using Boyfriend.Data;
using Boyfriend.Services;
using Boyfriend.Services.Update;
using JetBrains.Annotations;
using Remora.Commands.Attributes;
using Remora.Commands.Groups;
@ -203,7 +204,7 @@ public class BanCommandGroup : CommandGroup
/// was unbanned and vice-versa.
/// </returns>
/// <seealso cref="ExecuteBanAsync" />
/// <seealso cref="GuildUpdateService.TickGuildAsync" />
/// <seealso cref="MemberUpdateService.TickMemberDataAsync" />
[Command("unban")]
[DiscordDefaultMemberPermissions(DiscordPermission.BanMembers)]
[DiscordDefaultDMPermission(false)]

View file

@ -1,7 +1,6 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Remora.Discord.Commands.Contexts;
using Remora.Discord.Commands.Extensions;
using Remora.Discord.Commands.Services;
using Remora.Results;
@ -24,21 +23,14 @@ public class ErrorLoggingPostExecutionEvent : IPostExecutionEvent
/// Logs a warning using the injected <see cref="ILogger" /> if the <paramref name="commandResult" /> has not
/// succeeded.
/// </summary>
/// <param name="context">The context of the slash command. Unused.</param>
/// <param name="context">The context of the slash command.</param>
/// <param name="commandResult">The result whose success is checked.</param>
/// <param name="ct">The cancellation token for this operation. Unused.</param>
/// <returns>A result which has succeeded.</returns>
public Task<Result> AfterExecutionAsync(
ICommandContext context, IResult commandResult, CancellationToken ct = default)
{
if (!commandResult.IsSuccess && !commandResult.Error.IsUserOrEnvironmentError())
{
_logger.LogWarning("Error in slash command execution.\n{ErrorMessage}", commandResult.Error.Message);
if (commandResult.Error is ExceptionError exerr)
{
_logger.LogError(exerr.Exception, "An exception has been thrown");
}
}
_logger.LogResult(commandResult, $"Error in slash command execution for /{context.Command.Command.Node.Key}.");
return Task.FromResult(Result.FromSuccess());
}

View file

@ -1,7 +1,6 @@
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Remora.Discord.Commands.Contexts;
using Remora.Discord.Commands.Extensions;
using Remora.Discord.Commands.Services;
using Remora.Results;
@ -31,14 +30,7 @@ public class LoggingPreparationErrorEvent : IPreparationErrorEvent
public Task<Result> PreparationFailed(
IOperationContext context, IResult preparationResult, CancellationToken ct = default)
{
if (!preparationResult.IsSuccess && !preparationResult.Error.IsUserOrEnvironmentError())
{
_logger.LogWarning("Error in slash command preparation.\n{ErrorMessage}", preparationResult.Error.Message);
if (preparationResult.Error is ExceptionError exerr)
{
_logger.LogError(exerr.Exception, "An exception has been thrown");
}
}
_logger.LogResult(preparationResult, "Error in slash command preparation.");
return Task.FromResult(Result.FromSuccess());
}

View file

@ -2,6 +2,7 @@ using System.ComponentModel;
using System.Text;
using Boyfriend.Data;
using Boyfriend.Services;
using Boyfriend.Services.Update;
using JetBrains.Annotations;
using Remora.Commands.Attributes;
using Remora.Commands.Groups;
@ -166,7 +167,7 @@ public class MuteCommandGroup : CommandGroup
/// was unmuted and vice-versa.
/// </returns>
/// <seealso cref="ExecuteMute" />
/// <seealso cref="GuildUpdateService.TickGuildAsync" />
/// <seealso cref="MemberUpdateService.TickMemberDataAsync" />
[Command("unmute", "размут")]
[DiscordDefaultMemberPermissions(DiscordPermission.ModerateMembers)]
[DiscordDefaultDMPermission(false)]