diff --git a/src/Responders/GuildLoadedResponder.cs b/src/Responders/GuildLoadedResponder.cs index 3e08060..bbf4a0a 100644 --- a/src/Responders/GuildLoadedResponder.cs +++ b/src/Responders/GuildLoadedResponder.cs @@ -4,11 +4,11 @@ using Octobot.Data; using Octobot.Extensions; using Octobot.Services; using Remora.Discord.API.Abstractions.Gateway.Events; +using Remora.Discord.API.Abstractions.Objects; using Remora.Discord.API.Abstractions.Rest; using Remora.Discord.API.Gateway.Events; using Remora.Discord.Extensions.Embeds; using Remora.Discord.Gateway.Responders; -using Remora.Rest.Core; using Remora.Results; namespace Octobot.Responders; @@ -24,15 +24,17 @@ public class GuildLoadedResponder : IResponder private readonly GuildDataService _guildData; private readonly ILogger _logger; private readonly IDiscordRestUserAPI _userApi; + private readonly UtilityService _utility; public GuildLoadedResponder( IDiscordRestChannelAPI channelApi, GuildDataService guildData, ILogger logger, - IDiscordRestUserAPI userApi) + IDiscordRestUserAPI userApi, UtilityService utility) { _channelApi = channelApi; _guildData = guildData; _logger = logger; _userApi = userApi; + _utility = utility; } public async Task RespondAsync(IGuildCreate gatewayEvent, CancellationToken ct = default) @@ -59,20 +61,7 @@ public class GuildLoadedResponder : IResponder if (data.DataLoadFailed) { - var errorEmbed = new EmbedBuilder() - .WithSmallTitle(Messages.DataLoadFailedTitle, bot) - .WithDescription(Messages.DataLoadFailedDescription) - .WithFooter(Messages.ContactDevelopers) - .WithColour(ColorsList.Red) - .Build(); - - if (!errorEmbed.IsDefined(out var errorBuilt)) - { - return Result.FromError(errorEmbed); - } - - return (Result)await _channelApi.CreateMessageAsync( - GetEmergencyFeedbackChannel(guild, data), embeds: new[] { errorBuilt }, ct: ct); + return await SendDataLoadFailed(guild, data, bot, ct); } _logger.LogInformation("Loaded guild {ID} (\"{Name}\")", guild.ID, guild.Name); @@ -105,22 +94,27 @@ public class GuildLoadedResponder : IResponder GuildSettings.PrivateFeedbackChannel.Get(cfg), embeds: new[] { built }, ct: ct); } - private static Snowflake GetEmergencyFeedbackChannel(IGuildCreate.IAvailableGuild guild, GuildData data) + private async Task SendDataLoadFailed(IGuild guild, GuildData data, IUser bot, CancellationToken ct) { - var privateFeedback = GuildSettings.PrivateFeedbackChannel.Get(data.Settings); - if (!privateFeedback.Empty()) + var errorEmbed = new EmbedBuilder() + .WithSmallTitle(Messages.DataLoadFailedTitle, bot) + .WithDescription(Messages.DataLoadFailedDescription) + .WithFooter(Messages.ContactDevelopers) + .WithColour(ColorsList.Red) + .Build(); + + if (!errorEmbed.IsDefined(out var errorBuilt)) { - return privateFeedback; + return Result.FromError(errorEmbed); } - var publicFeedback = GuildSettings.PublicFeedbackChannel.Get(data.Settings); - if (!publicFeedback.Empty()) + var channelResult = await _utility.GetEmergencyFeedbackChannel(guild, data, ct); + if (!channelResult.IsDefined(out var channel)) { - return publicFeedback; + return Result.FromError(channelResult); } - return guild.SystemChannelID.AsOptional().IsDefined(out var systemChannel) - ? systemChannel - : guild.Channels[0].ID; + return (Result)await _channelApi.CreateMessageAsync( + channel, embeds: new[] { errorBuilt }, ct: ct); } } diff --git a/src/Services/Update/MemberUpdateService.cs b/src/Services/Update/MemberUpdateService.cs index ae099f6..b4289ce 100644 --- a/src/Services/Update/MemberUpdateService.cs +++ b/src/Services/Update/MemberUpdateService.cs @@ -29,14 +29,16 @@ public sealed partial class MemberUpdateService : BackgroundService private readonly IDiscordRestGuildAPI _guildApi; private readonly GuildDataService _guildData; private readonly ILogger _logger; + private readonly UtilityService _utility; public MemberUpdateService(IDiscordRestChannelAPI channelApi, IDiscordRestGuildAPI guildApi, - GuildDataService guildData, ILogger logger) + GuildDataService guildData, ILogger logger, UtilityService utility) { _channelApi = channelApi; _guildApi = guildApi; _guildData = guildData; _logger = logger; + _utility = utility; } protected override async Task ExecuteAsync(CancellationToken ct) @@ -90,21 +92,20 @@ public sealed partial class MemberUpdateService : BackgroundService return failedResults.AggregateErrors(); } + var interactionResult + = await _utility.CheckInteractionsAsync(guildId, null, id, "Update", ct); + if (!interactionResult.IsSuccess) + { + return Result.FromError(interactionResult); + } + + var canInteract = interactionResult.Entity is null; + if (data.MutedUntil is null) { data.Roles = guildMember.Roles.ToList().ConvertAll(r => r.Value); } - var autoUnmuteResult = await TryAutoUnmuteAsync(guildId, id, data, ct); - failedResults.AddIfFailed(autoUnmuteResult); - - if (!defaultRole.Empty() && !data.Roles.Contains(defaultRole.Value)) - { - var addResult = await _guildApi.AddGuildMemberRoleAsync( - guildId, id, defaultRole, ct: ct); - failedResults.AddIfFailed(addResult); - } - if (!guildMember.User.IsDefined(out var user)) { failedResults.AddIfFailed(new ArgumentNullError(nameof(guildMember.User))); @@ -117,6 +118,21 @@ public sealed partial class MemberUpdateService : BackgroundService failedResults.AddIfFailed(reminderTickResult); } + if (!canInteract) + { + return Result.FromSuccess(); + } + + var autoUnmuteResult = await TryAutoUnmuteAsync(guildId, id, data, ct); + failedResults.AddIfFailed(autoUnmuteResult); + + if (!defaultRole.Empty() && !data.Roles.Contains(defaultRole.Value)) + { + var addResult = await _guildApi.AddGuildMemberRoleAsync( + guildId, id, defaultRole, ct: ct); + failedResults.AddIfFailed(addResult); + } + if (GuildSettings.RenameHoistedUsers.Get(guildData.Settings)) { var filterResult = await FilterNicknameAsync(guildId, user, guildMember, ct); diff --git a/src/Services/UtilityService.cs b/src/Services/UtilityService.cs index 5bc06ea..d40570a 100644 --- a/src/Services/UtilityService.cs +++ b/src/Services/UtilityService.cs @@ -63,7 +63,7 @@ public sealed class UtilityService : IHostedService /// /// public async Task> CheckInteractionsAsync( - Snowflake guildId, Snowflake interacterId, Snowflake targetId, string action, CancellationToken ct = default) + Snowflake guildId, Snowflake? interacterId, Snowflake targetId, string action, CancellationToken ct = default) { if (interacterId == targetId) { @@ -100,7 +100,12 @@ public sealed class UtilityService : IHostedService return Result.FromError(rolesResult); } - var interacterResult = await _guildApi.GetGuildMemberAsync(guildId, interacterId, ct); + if (interacterId is null) + { + return CheckInteractions(action, guild, roles, targetMember, currentMember, currentMember); + } + + var interacterResult = await _guildApi.GetGuildMemberAsync(guildId, interacterId.Value, ct); return interacterResult.IsDefined(out var interacter) ? CheckInteractions(action, guild, roles, targetMember, currentMember, interacter) : Result.FromError(interacterResult); @@ -246,4 +251,30 @@ public sealed class UtilityService : IHostedService return Result.FromSuccess(); } + + public async Task> GetEmergencyFeedbackChannel(IGuild guild, GuildData data, CancellationToken ct) + { + var privateFeedback = GuildSettings.PrivateFeedbackChannel.Get(data.Settings); + if (!privateFeedback.Empty()) + { + return privateFeedback; + } + + var publicFeedback = GuildSettings.PublicFeedbackChannel.Get(data.Settings); + if (!publicFeedback.Empty()) + { + return publicFeedback; + } + + if (guild.SystemChannelID.AsOptional().IsDefined(out var systemChannel)) + { + return systemChannel; + } + + var channelsResult = await _guildApi.GetGuildChannelsAsync(guild.ID, ct); + + return channelsResult.IsDefined(out var channels) + ? channels[0].ID + : Result.FromError(channelsResult); + } }