diff --git a/.editorconfig b/.editorconfig index 4982036..ff9c068 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1022,7 +1022,7 @@ resharper_convert_to_constant_local_highlighting = warning resharper_convert_to_lambda_expression_highlighting = warning resharper_convert_to_local_function_highlighting = warning resharper_convert_to_null_coalescing_compound_assignment_highlighting = warning -resharper_convert_to_primary_constructor_highlighting = warning +resharper_convert_to_primary_constructor_highlighting = none resharper_convert_to_static_class_highlighting = warning resharper_convert_to_using_declaration_highlighting = warning resharper_convert_type_check_pattern_to_null_check_highlighting = warning diff --git a/Octobot.csproj b/Octobot.csproj index 7d3500b..5258c89 100644 --- a/Octobot.csproj +++ b/Octobot.csproj @@ -25,6 +25,7 @@ + diff --git a/docs/README.md b/docs/README.md index cdd9ced..10ee63c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -24,7 +24,7 @@ Veemo! I'm a general-purpose bot for moderation (formerly known as Boyfriend) wr ## Running Octobot -1. Install [.NET 7 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) +1. Install [.NET 8 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) 2. Go to the [Discord Developer Portal](https://discord.com/developers), create a new application and get a bot token. Don't forget to also enable all intents! 3. Clone this repository and open `Octobot` folder. ``` diff --git a/src/Commands/AboutCommandGroup.cs b/src/Commands/AboutCommandGroup.cs index e491470..45077e6 100644 --- a/src/Commands/AboutCommandGroup.cs +++ b/src/Commands/AboutCommandGroup.cs @@ -99,6 +99,6 @@ public class AboutCommandGroup : CommandGroup .WithImageUrl("https://cdn.mctaylors.ru/octobot-banner.png") .Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Commands/BanCommandGroup.cs b/src/Commands/BanCommandGroup.cs index 3f89819..f0da978 100644 --- a/src/Commands/BanCommandGroup.cs +++ b/src/Commands/BanCommandGroup.cs @@ -117,7 +117,7 @@ public class BanCommandGroup : CommandGroup var failedEmbed = new EmbedBuilder().WithSmallTitle(Messages.UserAlreadyBanned, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var interactionResult @@ -132,7 +132,7 @@ public class BanCommandGroup : CommandGroup var errorEmbed = new EmbedBuilder().WithSmallTitle(interactionResult.Entity, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(errorEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(errorEmbed, ct: ct); } var builder = new StringBuilder().AppendBulletPointLine(string.Format(Messages.DescriptionActionReason, reason)); @@ -158,12 +158,7 @@ public class BanCommandGroup : CommandGroup .WithColour(ColorsList.Red) .Build(); - if (!dmEmbed.IsDefined(out var dmBuilt)) - { - return Result.FromError(dmEmbed); - } - - await _channelApi.CreateMessageAsync(dmChannel.ID, embeds: new[] { dmBuilt }, ct: ct); + await _channelApi.CreateMessageWithEmbedResultAsync(dmChannel.ID, embedResult: dmEmbed, ct: ct); } var banResult = await _guildApi.CreateGuildBanAsync( @@ -190,7 +185,7 @@ public class BanCommandGroup : CommandGroup return Result.FromError(logResult.Error); } - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } /// @@ -255,7 +250,7 @@ public class BanCommandGroup : CommandGroup var errorEmbed = new EmbedBuilder().WithSmallTitle(Messages.UserNotBanned, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(errorEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(errorEmbed, ct: ct); } var unbanResult = await _guildApi.RemoveGuildBanAsync( @@ -281,6 +276,6 @@ public class BanCommandGroup : CommandGroup return Result.FromError(logResult.Error); } - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Commands/ClearCommandGroup.cs b/src/Commands/ClearCommandGroup.cs index 8e1f90d..7ebd4ea 100644 --- a/src/Commands/ClearCommandGroup.cs +++ b/src/Commands/ClearCommandGroup.cs @@ -121,7 +121,7 @@ public class ClearCommandGroup : CommandGroup var failedEmbed = new EmbedBuilder().WithSmallTitle(Messages.NoMessagesToClear, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var title = author is not null @@ -146,6 +146,6 @@ public class ClearCommandGroup : CommandGroup var embed = new EmbedBuilder().WithSmallTitle(title, bot) .WithColour(ColorsList.Green).Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Commands/Events/ErrorLoggingPostExecutionEvent.cs b/src/Commands/Events/ErrorLoggingPostExecutionEvent.cs index 426fd35..2d5f606 100644 --- a/src/Commands/Events/ErrorLoggingPostExecutionEvent.cs +++ b/src/Commands/Events/ErrorLoggingPostExecutionEvent.cs @@ -65,6 +65,6 @@ public class ErrorLoggingPostExecutionEvent : IPostExecutionEvent .WithColour(ColorsList.Red) .Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Commands/KickCommandGroup.cs b/src/Commands/KickCommandGroup.cs index f2a840d..cad8ea9 100644 --- a/src/Commands/KickCommandGroup.cs +++ b/src/Commands/KickCommandGroup.cs @@ -104,7 +104,7 @@ public class KickCommandGroup : CommandGroup var embed = new EmbedBuilder().WithSmallTitle(Messages.UserNotFoundShort, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, CancellationToken); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: CancellationToken); } return await KickUserAsync(executor, target, reason, guild, channelId, data, bot, CancellationToken); @@ -126,7 +126,7 @@ public class KickCommandGroup : CommandGroup var failedEmbed = new EmbedBuilder().WithSmallTitle(interactionResult.Entity, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var dmChannelResult = await _userApi.CreateDMAsync(target.ID, ct); @@ -140,12 +140,7 @@ public class KickCommandGroup : CommandGroup .WithColour(ColorsList.Red) .Build(); - if (!dmEmbed.IsDefined(out var dmBuilt)) - { - return Result.FromError(dmEmbed); - } - - await _channelApi.CreateMessageAsync(dmChannel.ID, embeds: new[] { dmBuilt }, ct: ct); + await _channelApi.CreateMessageWithEmbedResultAsync(dmChannel.ID, embedResult: dmEmbed, ct: ct); } var kickResult = await _guildApi.RemoveGuildMemberAsync( @@ -171,6 +166,6 @@ public class KickCommandGroup : CommandGroup string.Format(Messages.UserKicked, target.GetTag()), target) .WithColour(ColorsList.Green).Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Commands/MuteCommandGroup.cs b/src/Commands/MuteCommandGroup.cs index 2ce06ae..6a28f38 100644 --- a/src/Commands/MuteCommandGroup.cs +++ b/src/Commands/MuteCommandGroup.cs @@ -101,7 +101,7 @@ public class MuteCommandGroup : CommandGroup var embed = new EmbedBuilder().WithSmallTitle(Messages.UserNotFoundShort, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, CancellationToken); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: CancellationToken); } return await MuteUserAsync(executor, target, reason, duration, guildId, data, channelId, bot, CancellationToken); @@ -124,7 +124,7 @@ public class MuteCommandGroup : CommandGroup var failedEmbed = new EmbedBuilder().WithSmallTitle(interactionResult.Entity, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var until = DateTimeOffset.UtcNow.Add(duration); // >:) @@ -151,7 +151,7 @@ public class MuteCommandGroup : CommandGroup string.Format(Messages.UserMuted, target.GetTag()), target) .WithColour(ColorsList.Green).Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } private async Task SelectMuteMethodAsync( @@ -202,7 +202,7 @@ public class MuteCommandGroup : CommandGroup .WithDescription(Messages.DurationRequiredForTimeOuts) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var muteResult = await _guildApi.ModifyGuildMemberAsync( @@ -266,7 +266,7 @@ public class MuteCommandGroup : CommandGroup var embed = new EmbedBuilder().WithSmallTitle(Messages.UserNotFoundShort, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, CancellationToken); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: CancellationToken); } return await RemoveMuteAsync(executor, target, reason, guildId, data, channelId, bot, CancellationToken); @@ -289,7 +289,7 @@ public class MuteCommandGroup : CommandGroup var failedEmbed = new EmbedBuilder().WithSmallTitle(interactionResult.Entity, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var guildMemberResult = await _guildApi.GetGuildMemberAsync(guildId, target.ID, ct); @@ -307,7 +307,7 @@ public class MuteCommandGroup : CommandGroup var failedEmbed = new EmbedBuilder().WithSmallTitle(Messages.UserNotMuted, bot) .WithColour(ColorsList.Red).Build(); - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var removeMuteRoleAsync = @@ -337,7 +337,7 @@ public class MuteCommandGroup : CommandGroup string.Format(Messages.UserUnmuted, target.GetTag()), target) .WithColour(ColorsList.Green).Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } private async Task RemoveMuteRoleAsync( diff --git a/src/Commands/PingCommandGroup.cs b/src/Commands/PingCommandGroup.cs index 84b15a0..31fa6dc 100644 --- a/src/Commands/PingCommandGroup.cs +++ b/src/Commands/PingCommandGroup.cs @@ -97,6 +97,6 @@ public class PingCommandGroup : CommandGroup .WithCurrentTimestamp() .Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Commands/RemindCommandGroup.cs b/src/Commands/RemindCommandGroup.cs index 79a583b..67e7910 100644 --- a/src/Commands/RemindCommandGroup.cs +++ b/src/Commands/RemindCommandGroup.cs @@ -26,19 +26,21 @@ namespace Octobot.Commands; [UsedImplicitly] public class RemindCommandGroup : CommandGroup { - private readonly ICommandContext _context; + private readonly IInteractionCommandContext _context; private readonly IFeedbackService _feedback; private readonly GuildDataService _guildData; private readonly IDiscordRestUserAPI _userApi; + private readonly IDiscordRestInteractionAPI _interactionApi; public RemindCommandGroup( - ICommandContext context, GuildDataService guildData, IFeedbackService feedback, - IDiscordRestUserAPI userApi) + IInteractionCommandContext context, GuildDataService guildData, IFeedbackService feedback, + IDiscordRestUserAPI userApi, IDiscordRestInteractionAPI interactionApi) { _context = context; _guildData = guildData; _feedback = feedback; _userApi = userApi; + _interactionApi = interactionApi; } /// @@ -72,10 +74,10 @@ public class RemindCommandGroup : CommandGroup var data = await _guildData.GetData(guildId, CancellationToken); Messages.Culture = GuildSettings.Language.Get(data.Settings); - return await ListRemindersAsync(data.GetOrCreateMemberData(executorId), executor, bot, CancellationToken); + return await ListRemindersAsync(data.GetOrCreateMemberData(executorId), guildId, executor, bot, CancellationToken); } - private Task ListRemindersAsync(MemberData data, IUser executor, IUser bot, CancellationToken ct) + private Task ListRemindersAsync(MemberData data, Snowflake guildId, IUser executor, IUser bot, CancellationToken ct) { if (data.Reminders.Count == 0) { @@ -83,7 +85,7 @@ public class RemindCommandGroup : CommandGroup .WithColour(ColorsList.Red) .Build(); - return _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var builder = new StringBuilder(); @@ -92,7 +94,8 @@ public class RemindCommandGroup : CommandGroup var reminder = data.Reminders[i]; builder.AppendBulletPointLine(string.Format(Messages.ReminderPosition, Markdown.InlineCode((i + 1).ToString()))) .AppendSubBulletPointLine(string.Format(Messages.ReminderText, Markdown.InlineCode(reminder.Text))) - .AppendSubBulletPointLine(string.Format(Messages.ReminderTime, Markdown.Timestamp(reminder.At))); + .AppendSubBulletPointLine(string.Format(Messages.ReminderTime, Markdown.Timestamp(reminder.At))) + .AppendSubBulletPointLine(string.Format(Messages.DescriptionActionJumpToMessage, $"https://discord.com/channels/{guildId.Value}/{reminder.ChannelId}/{reminder.MessageId}")); } var embed = new EmbedBuilder().WithSmallTitle( @@ -101,8 +104,7 @@ public class RemindCommandGroup : CommandGroup .WithColour(ColorsList.Cyan) .Build(); - return _feedback.SendContextualEmbedResultAsync( - embed, ct); + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } /// @@ -139,25 +141,29 @@ public class RemindCommandGroup : CommandGroup return await AddReminderAsync(@in, text, data, channelId, executor, CancellationToken); } - private Task AddReminderAsync( - TimeSpan @in, string text, GuildData data, + private async Task AddReminderAsync(TimeSpan @in, string text, GuildData data, Snowflake channelId, IUser executor, CancellationToken ct = default) { - var remindAt = DateTimeOffset.UtcNow.Add(@in); var memberData = data.GetOrCreateMemberData(executor.ID); + var remindAt = DateTimeOffset.UtcNow.Add(@in); + var responseResult = await _interactionApi.GetOriginalInteractionResponseAsync(_context.Interaction.ApplicationID, _context.Interaction.Token, ct); + if (!responseResult.IsDefined(out var response)) + { + return (Result)responseResult; + } memberData.Reminders.Add( new Reminder { At = remindAt, - Channel = channelId.Value, - Text = text + ChannelId = channelId.Value, + Text = text, + MessageId = response.ID.Value }); - var builder = new StringBuilder().AppendBulletPointLine(string.Format( - Messages.ReminderText, Markdown.InlineCode(text))) + var builder = new StringBuilder() + .AppendBulletPointLine(string.Format(Messages.ReminderText, Markdown.InlineCode(text))) .AppendBulletPoint(string.Format(Messages.ReminderTime, Markdown.Timestamp(remindAt))); - var embed = new EmbedBuilder().WithSmallTitle( string.Format(Messages.ReminderCreated, executor.GetTag()), executor) .WithDescription(builder.ToString()) @@ -165,7 +171,7 @@ public class RemindCommandGroup : CommandGroup .WithFooter(string.Format(Messages.ReminderPosition, memberData.Reminders.Count)) .Build(); - return _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } /// @@ -208,7 +214,7 @@ public class RemindCommandGroup : CommandGroup .WithColour(ColorsList.Red) .Build(); - return _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var reminder = data.Reminders[index]; @@ -224,7 +230,6 @@ public class RemindCommandGroup : CommandGroup .WithColour(ColorsList.Green) .Build(); - return _feedback.SendContextualEmbedResultAsync( - embed, ct); + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Commands/SettingsCommandGroup.cs b/src/Commands/SettingsCommandGroup.cs index 60323d7..a8891bd 100644 --- a/src/Commands/SettingsCommandGroup.cs +++ b/src/Commands/SettingsCommandGroup.cs @@ -124,7 +124,7 @@ public class SettingsCommandGroup : CommandGroup .WithColour(ColorsList.Red) .Build(); - return _feedback.SendContextualEmbedResultAsync(errorEmbed, ct); + return _feedback.SendContextualEmbedResultAsync(errorEmbed, ct: ct); } footer.Append($"{Messages.Page} {page}/{totalPages} "); @@ -149,7 +149,7 @@ public class SettingsCommandGroup : CommandGroup .WithFooter(footer.ToString()) .Build(); - return _feedback.SendContextualEmbedResultAsync(embed, ct); + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } /// @@ -207,7 +207,7 @@ public class SettingsCommandGroup : CommandGroup .WithColour(ColorsList.Red) .Build(); - return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct); + return await _feedback.SendContextualEmbedResultAsync(failedEmbed, ct: ct); } var builder = new StringBuilder(); @@ -230,7 +230,7 @@ public class SettingsCommandGroup : CommandGroup .WithColour(ColorsList.Green) .Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } /// @@ -284,7 +284,7 @@ public class SettingsCommandGroup : CommandGroup .WithColour(ColorsList.Green) .Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } private async Task ResetAllSettingsAsync(JsonNode cfg, IUser bot, @@ -305,6 +305,6 @@ public class SettingsCommandGroup : CommandGroup .WithColour(ColorsList.Green) .Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Commands/ToolsCommandGroup.cs b/src/Commands/ToolsCommandGroup.cs index be4c2c1..78058cb 100644 --- a/src/Commands/ToolsCommandGroup.cs +++ b/src/Commands/ToolsCommandGroup.cs @@ -163,7 +163,7 @@ public class ToolsCommandGroup : CommandGroup .WithFooter($"ID: {target.ID.ToString()}") .Build(); - return await _feedback.SendContextualEmbedResultAsync(embed, ct); + return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } private static Color AppendGuildInformation(Color color, IGuildMember guildMember, StringBuilder builder) @@ -312,7 +312,7 @@ public class ToolsCommandGroup : CommandGroup .WithFooter($"ID: {guild.ID.ToString()}") .Build(); - return _feedback.SendContextualEmbedResultAsync(embed, ct); + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } /// @@ -389,7 +389,7 @@ public class ToolsCommandGroup : CommandGroup .WithColour(embedColor) .Build(); - return _feedback.SendContextualEmbedResultAsync(embed, ct); + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } private static readonly TimestampStyle[] AllStyles = @@ -459,6 +459,6 @@ public class ToolsCommandGroup : CommandGroup .WithColour(ColorsList.Blue) .Build(); - return _feedback.SendContextualEmbedResultAsync(embed, ct); + return _feedback.SendContextualEmbedResultAsync(embed, ct: ct); } } diff --git a/src/Data/Reminder.cs b/src/Data/Reminder.cs index 42144f9..f21b222 100644 --- a/src/Data/Reminder.cs +++ b/src/Data/Reminder.cs @@ -4,5 +4,6 @@ public struct Reminder { public DateTimeOffset At { get; init; } public string Text { get; init; } - public ulong Channel { get; init; } + public ulong ChannelId { get; init; } + public ulong MessageId { get; init; } } diff --git a/src/Extensions/ChannelApiExtensions.cs b/src/Extensions/ChannelApiExtensions.cs new file mode 100644 index 0000000..12ccf35 --- /dev/null +++ b/src/Extensions/ChannelApiExtensions.cs @@ -0,0 +1,29 @@ +using OneOf; +using Remora.Discord.API.Abstractions.Objects; +using Remora.Discord.API.Abstractions.Rest; +using Remora.Discord.API.Objects; +using Remora.Rest.Core; +using Remora.Results; + +namespace Octobot.Extensions; + +public static class ChannelApiExtensions +{ + public static async Task CreateMessageWithEmbedResultAsync(this IDiscordRestChannelAPI channelApi, + Snowflake channelId, Optional message = default, Optional nonce = default, + Optional isTextToSpeech = default, Optional> embedResult = default, + Optional allowedMentions = default, Optional messageRefenence = default, + Optional> components = default, + Optional> stickerIds = default, + Optional>> attachments = default, + Optional flags = default, CancellationToken ct = default) + { + if (!embedResult.IsDefined() || !embedResult.Value.IsDefined(out var embed)) + { + return Result.FromError(embedResult.Value); + } + + return (Result)await channelApi.CreateMessageAsync(channelId, message, nonce, isTextToSpeech, new[] { embed }, + allowedMentions, messageRefenence, components, stickerIds, attachments, flags, ct); + } +} diff --git a/src/Extensions/FeedbackServiceExtensions.cs b/src/Extensions/FeedbackServiceExtensions.cs index 739aa34..40e0d53 100644 --- a/src/Extensions/FeedbackServiceExtensions.cs +++ b/src/Extensions/FeedbackServiceExtensions.cs @@ -1,4 +1,5 @@ using Remora.Discord.API.Objects; +using Remora.Discord.Commands.Feedback.Messages; using Remora.Discord.Commands.Feedback.Services; using Remora.Results; @@ -7,13 +8,14 @@ namespace Octobot.Extensions; public static class FeedbackServiceExtensions { public static async Task SendContextualEmbedResultAsync( - this IFeedbackService feedback, Result embedResult, CancellationToken ct = default) + this IFeedbackService feedback, Result embedResult, + FeedbackMessageOptions? options = null, CancellationToken ct = default) { if (!embedResult.IsDefined(out var embed)) { return Result.FromError(embedResult); } - return (Result)await feedback.SendContextualEmbedAsync(embed, ct: ct); + return (Result)await feedback.SendContextualEmbedAsync(embed, options, ct); } } diff --git a/src/Responders/GuildLoadedResponder.cs b/src/Responders/GuildLoadedResponder.cs index 5d5d68a..cc720c8 100644 --- a/src/Responders/GuildLoadedResponder.cs +++ b/src/Responders/GuildLoadedResponder.cs @@ -92,17 +92,19 @@ public class GuildLoadedResponder : IResponder .WithCurrentTimestamp() .WithColour(ColorsList.Blue) .Build(); - if (!embed.IsDefined(out var built)) - { - return Result.FromError(embed); - } - return (Result)await _channelApi.CreateMessageAsync( - GuildSettings.PrivateFeedbackChannel.Get(cfg), embeds: new[] { built }, ct: ct); + return await _channelApi.CreateMessageWithEmbedResultAsync( + GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed, ct: ct); } private async Task SendDataLoadFailed(IGuild guild, GuildData data, IUser bot, CancellationToken ct) { + var channelResult = await _utility.GetEmergencyFeedbackChannel(guild, data, ct); + if (!channelResult.IsDefined(out var channel)) + { + return Result.FromError(channelResult); + } + var errorEmbed = new EmbedBuilder() .WithSmallTitle(Messages.DataLoadFailedTitle, bot) .WithDescription(Messages.DataLoadFailedDescription) @@ -110,18 +112,7 @@ public class GuildLoadedResponder : IResponder .WithColour(ColorsList.Red) .Build(); - if (!errorEmbed.IsDefined(out var errorBuilt)) - { - return Result.FromError(errorEmbed); - } - - var channelResult = await _utility.GetEmergencyFeedbackChannel(guild, data, ct); - if (!channelResult.IsDefined(out var channel)) - { - return Result.FromError(channelResult); - } - - return (Result)await _channelApi.CreateMessageAsync( - channel, embeds: new[] { errorBuilt }, ct: ct); + return await _channelApi.CreateMessageWithEmbedResultAsync( + channel, embedResult: errorEmbed, ct: ct); } } diff --git a/src/Responders/GuildMemberJoinedResponder.cs b/src/Responders/GuildMemberJoinedResponder.cs index 09075bf..66faa28 100644 --- a/src/Responders/GuildMemberJoinedResponder.cs +++ b/src/Responders/GuildMemberJoinedResponder.cs @@ -72,13 +72,9 @@ public class GuildMemberJoinedResponder : IResponder .WithTimestamp(gatewayEvent.JoinedAt) .WithColour(ColorsList.Green) .Build(); - if (!embed.IsDefined(out var built)) - { - return Result.FromError(embed); - } - return (Result)await _channelApi.CreateMessageAsync( - GuildSettings.PublicFeedbackChannel.Get(cfg), embeds: new[] { built }, + return await _channelApi.CreateMessageWithEmbedResultAsync( + GuildSettings.PublicFeedbackChannel.Get(cfg), embedResult: embed, allowedMentions: Octobot.NoMentions, ct: ct); } diff --git a/src/Responders/MessageDeletedResponder.cs b/src/Responders/MessageDeletedResponder.cs index 5e4870b..bfedb22 100644 --- a/src/Responders/MessageDeletedResponder.cs +++ b/src/Responders/MessageDeletedResponder.cs @@ -98,13 +98,9 @@ public class MessageDeletedResponder : IResponder .WithTimestamp(message.Timestamp) .WithColour(ColorsList.Red) .Build(); - if (!embed.IsDefined(out var built)) - { - return Result.FromError(embed); - } - return (Result)await _channelApi.CreateMessageAsync( - GuildSettings.PrivateFeedbackChannel.Get(cfg), embeds: new[] { built }, + return await _channelApi.CreateMessageWithEmbedResultAsync( + GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed, allowedMentions: Octobot.NoMentions, ct: ct); } } diff --git a/src/Responders/MessageEditedResponder.cs b/src/Responders/MessageEditedResponder.cs index 243aed3..d4455c0 100644 --- a/src/Responders/MessageEditedResponder.cs +++ b/src/Responders/MessageEditedResponder.cs @@ -112,13 +112,9 @@ public class MessageEditedResponder : IResponder .WithTimestamp(timestamp.Value) .WithColour(ColorsList.Yellow) .Build(); - if (!embed.IsDefined(out var built)) - { - return Result.FromError(embed); - } - return (Result)await _channelApi.CreateMessageAsync( - GuildSettings.PrivateFeedbackChannel.Get(cfg), embeds: new[] { built }, + return await _channelApi.CreateMessageWithEmbedResultAsync( + GuildSettings.PrivateFeedbackChannel.Get(cfg), embedResult: embed, allowedMentions: Octobot.NoMentions, ct: ct); } } diff --git a/src/Services/Update/MemberUpdateService.cs b/src/Services/Update/MemberUpdateService.cs index b4289ce..e7860ae 100644 --- a/src/Services/Update/MemberUpdateService.cs +++ b/src/Services/Update/MemberUpdateService.cs @@ -1,3 +1,4 @@ +using System.Text; using System.Text.RegularExpressions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -114,7 +115,7 @@ public sealed partial class MemberUpdateService : BackgroundService for (var i = data.Reminders.Count - 1; i >= 0; i--) { - var reminderTickResult = await TickReminderAsync(data.Reminders[i], user, data, ct); + var reminderTickResult = await TickReminderAsync(data.Reminders[i], user, data, guildId, ct); failedResults.AddIfFailed(reminderTickResult); } @@ -217,30 +218,29 @@ public sealed partial class MemberUpdateService : BackgroundService [GeneratedRegex("[^0-9A-Za-zА-Яа-яЁё]")] private static partial Regex IllegalChars(); - private async Task TickReminderAsync(Reminder reminder, IUser user, MemberData data, CancellationToken ct) + private async Task TickReminderAsync(Reminder reminder, IUser user, MemberData data, Snowflake guildId, + CancellationToken ct) { if (DateTimeOffset.UtcNow < reminder.At) { return Result.FromSuccess(); } + var builder = new StringBuilder() + .AppendBulletPointLine(string.Format(Messages.DescriptionReminder, Markdown.InlineCode(reminder.Text))) + .AppendBulletPointLine(string.Format(Messages.DescriptionActionJumpToMessage, $"https://discord.com/channels/{guildId.Value}/{reminder.ChannelId}/{reminder.MessageId}")); + var embed = new EmbedBuilder().WithSmallTitle( string.Format(Messages.Reminder, user.GetTag()), user) - .WithDescription( - string.Format(Messages.DescriptionReminder, Markdown.InlineCode(reminder.Text))) + .WithDescription(builder.ToString()) .WithColour(ColorsList.Magenta) .Build(); - if (!embed.IsDefined(out var built)) - { - return Result.FromError(embed); - } - - var messageResult = await _channelApi.CreateMessageAsync( - reminder.Channel.ToSnowflake(), Mention.User(user), embeds: new[] { built }, ct: ct); + var messageResult = await _channelApi.CreateMessageWithEmbedResultAsync( + reminder.ChannelId.ToSnowflake(), Mention.User(user), embedResult: embed, ct: ct); if (!messageResult.IsSuccess) { - return Result.FromError(messageResult); + return messageResult; } data.Reminders.Remove(reminder); diff --git a/src/Services/Update/ScheduledEventUpdateService.cs b/src/Services/Update/ScheduledEventUpdateService.cs index 9ec9fcf..38fe4a7 100644 --- a/src/Services/Update/ScheduledEventUpdateService.cs +++ b/src/Services/Update/ScheduledEventUpdateService.cs @@ -215,10 +215,6 @@ public sealed class ScheduledEventUpdateService : BackgroundService .WithCurrentTimestamp() .WithColour(ColorsList.White) .Build(); - if (!embed.IsDefined(out var built)) - { - return Result.FromError(embed); - } var roleMention = !GuildSettings.EventNotificationRole.Get(settings).Empty() ? Mention.Role(GuildSettings.EventNotificationRole.Get(settings)) @@ -231,8 +227,8 @@ public sealed class ScheduledEventUpdateService : BackgroundService URL: $"https://discord.com/events/{scheduledEvent.GuildID}/{scheduledEvent.ID}" ); - return (Result)await _channelApi.CreateMessageAsync( - GuildSettings.EventNotificationChannel.Get(settings), roleMention, embeds: new[] { built }, + return await _channelApi.CreateMessageWithEmbedResultAsync( + GuildSettings.EventNotificationChannel.Get(settings), roleMention, embedResult: embed, components: new[] { new ActionRowComponent(new[] { button }) }, ct: ct); } @@ -317,14 +313,9 @@ public sealed class ScheduledEventUpdateService : BackgroundService .WithCurrentTimestamp() .Build(); - if (!startedEmbed.IsDefined(out var startedBuilt)) - { - return Result.FromError(startedEmbed); - } - - return (Result)await _channelApi.CreateMessageAsync( + return await _channelApi.CreateMessageWithEmbedResultAsync( GuildSettings.EventNotificationChannel.Get(data.Settings), - content, embeds: new[] { startedBuilt }, ct: ct); + content, embedResult: startedEmbed, ct: ct); } private async Task SendScheduledEventCompletedMessage(ScheduledEventData eventData, GuildData data, @@ -348,14 +339,9 @@ public sealed class ScheduledEventUpdateService : BackgroundService .WithCurrentTimestamp() .Build(); - if (!completedEmbed.IsDefined(out var completedBuilt)) - { - return Result.FromError(completedEmbed); - } - - var createResult = (Result)await _channelApi.CreateMessageAsync( + var createResult = await _channelApi.CreateMessageWithEmbedResultAsync( GuildSettings.EventNotificationChannel.Get(data.Settings), - embeds: new[] { completedBuilt }, ct: ct); + embedResult: completedEmbed, ct: ct); if (createResult.IsSuccess) { data.ScheduledEvents.Remove(eventData.Id); @@ -380,13 +366,8 @@ public sealed class ScheduledEventUpdateService : BackgroundService .WithCurrentTimestamp() .Build(); - if (!embed.IsDefined(out var built)) - { - return Result.FromError(embed); - } - - var createResult = (Result)await _channelApi.CreateMessageAsync( - GuildSettings.EventNotificationChannel.Get(data.Settings), embeds: new[] { built }, ct: ct); + var createResult = await _channelApi.CreateMessageWithEmbedResultAsync( + GuildSettings.EventNotificationChannel.Get(data.Settings), embedResult: embed, ct: ct); if (createResult.IsSuccess) { data.ScheduledEvents.Remove(eventData.Id); @@ -445,14 +426,9 @@ public sealed class ScheduledEventUpdateService : BackgroundService .WithColour(ColorsList.Default) .Build(); - if (!earlyResult.IsDefined(out var earlyBuilt)) - { - return Result.FromError(earlyResult); - } - - return (Result)await _channelApi.CreateMessageAsync( + return await _channelApi.CreateMessageWithEmbedResultAsync( GuildSettings.EventNotificationChannel.Get(data.Settings), content, - embeds: new[] { earlyBuilt }, ct: ct); + embedResult: earlyResult, ct: ct); } } diff --git a/src/Services/UtilityService.cs b/src/Services/UtilityService.cs index d40570a..9ac481b 100644 --- a/src/Services/UtilityService.cs +++ b/src/Services/UtilityService.cs @@ -226,26 +226,19 @@ public sealed class UtilityService : IHostedService .WithColour(color) .Build(); - if (!logEmbed.IsDefined(out var logBuilt)) - { - return Result.FromError(logEmbed); - } - - var builtArray = new[] { logBuilt }; - // Not awaiting to reduce response time if (isPublic && publicChannel != channelId) { - _ = _channelApi.CreateMessageAsync( - publicChannel, embeds: builtArray, + _ = _channelApi.CreateMessageWithEmbedResultAsync( + publicChannel, embedResult: logEmbed, ct: ct); } if (privateChannel != publicChannel && privateChannel != channelId) { - _ = _channelApi.CreateMessageAsync( - privateChannel, embeds: builtArray, + _ = _channelApi.CreateMessageWithEmbedResultAsync( + privateChannel, embedResult: logEmbed, ct: ct); }