From e883e143ebe90bcc76342e7cd67fec9f4e74f284 Mon Sep 17 00:00:00 2001 From: Octol1ttle Date: Sun, 11 Jun 2023 14:12:17 +0500 Subject: [PATCH] Add xmldocs. Signed-off-by: Octol1ttle --- ColorsList.cs | 3 + Commands/BanCommandGroup.cs | 43 +++++++++-- Commands/ErrorLoggingPostExecutionEvent.cs | 11 +++ Data/GuildConfiguration.cs | 75 +++++++++++++++---- Data/GuildData.cs | 8 ++- Data/ScheduledEventData.cs | 6 +- EventResponders.cs | 84 ++++++++++++++++------ Extensions.cs | 40 ++++++++++- InteractionResponders.cs | 8 +++ Messages.Designer.cs | 4 +- Messages.resx | 6 +- Messages.ru.resx | 6 +- Messages.tt-ru.resx | 6 +- Services/Data/GuildDataService.cs | 3 + Services/UtilityService.cs | 22 ++++++ 15 files changed, 271 insertions(+), 54 deletions(-) diff --git a/ColorsList.cs b/ColorsList.cs index ee7a0b5..fc66573 100644 --- a/ColorsList.cs +++ b/ColorsList.cs @@ -5,6 +5,9 @@ namespace Boyfriend; +/// +/// Contains all colors used in embeds. +/// public static class ColorsList { public static readonly Color Default = Color.Gray; public static readonly Color Red = Color.Firebrick; diff --git a/Commands/BanCommandGroup.cs b/Commands/BanCommandGroup.cs index e773f48..92ed248 100644 --- a/Commands/BanCommandGroup.cs +++ b/Commands/BanCommandGroup.cs @@ -19,6 +19,9 @@ using Remora.Results; namespace Boyfriend.Commands; +/// +/// Handles commands related to ban management: /ban and unban. +/// public class BanCommandGroup : CommandGroup { private readonly IDiscordRestChannelAPI _channelApi; private readonly ICommandContext _context; @@ -41,12 +44,26 @@ public class BanCommandGroup : CommandGroup { _utility = utility; } - [Command("ban")] + /// + /// A slash command that bans a Discord user with the specified reason. + /// + /// The user to ban. + /// + /// The reason for this ban. Must be encoded with when passed to + /// . + /// + /// + /// A feedback sending result which may or may not have succeeded. A successful result does not mean that the user + /// was banned and vice-versa. + /// + /// + [Command("ban", "бан")] [RequireContext(ChannelContext.Guild)] [RequireDiscordPermission(DiscordPermission.BanMembers)] [RequireBotDiscordPermissions(DiscordPermission.BanMembers)] [Description("банит пидора")] public async Task BanUserAsync([Description("Юзер, кого банить")] IUser target, string reason) { + // Data checks if (!_context.TryGetGuildID(out var guildId)) return Result.FromError(new ArgumentNullError(nameof(guildId))); if (!_context.TryGetUserID(out var userId)) @@ -54,6 +71,7 @@ public class BanCommandGroup : CommandGroup { if (!_context.TryGetChannelID(out var channelId)) return Result.FromError(new ArgumentNullError(nameof(channelId))); + // The current user's avatar is used when sending error messages var currentUserResult = await _userApi.GetCurrentUserAsync(CancellationToken); if (!currentUserResult.IsDefined(out var currentUser)) return Result.FromError(currentUserResult); @@ -110,6 +128,7 @@ public class BanCommandGroup : CommandGroup { return Result.FromError(logEmbed); var builtArray = new[] { logBuilt }; + // Not awaiting to reduce response time if (cfg.PrivateFeedbackChannel != channelId.Value) _ = _channelApi.CreateMessageAsync( cfg.PrivateFeedbackChannel.ToDiscordSnowflake(), embeds: builtArray, @@ -127,12 +146,26 @@ public class BanCommandGroup : CommandGroup { return (Result)await _feedbackService.SendContextualEmbedAsync(built, ct: CancellationToken); } + /// + /// A slash command that unbans a Discord user with the specified reason. + /// + /// The user to unban. + /// + /// The reason for this unban. Must be encoded with when passed to + /// . + /// + /// + /// A feedback sending result which may or may not have succeeded. A successful result does not mean that the user + /// was unbanned and vice-versa. + /// + /// [Command("unban")] [RequireContext(ChannelContext.Guild)] [RequireDiscordPermission(DiscordPermission.BanMembers)] [RequireBotDiscordPermissions(DiscordPermission.BanMembers)] [Description("разбанит пидора")] public async Task UnBanUserAsync([Description("Юзер, кого разбанить")] IUser target, string reason) { + // Data checks if (!_context.TryGetGuildID(out var guildId)) return Result.FromError(new ArgumentNullError(nameof(guildId))); if (!_context.TryGetUserID(out var userId)) @@ -140,6 +173,7 @@ public class BanCommandGroup : CommandGroup { if (!_context.TryGetChannelID(out var channelId)) return Result.FromError(new ArgumentNullError(nameof(channelId))); + // The current user's avatar is used when sending error messages var currentUserResult = await _userApi.GetCurrentUserAsync(CancellationToken); if (!currentUserResult.IsDefined(out var currentUser)) return Result.FromError(currentUserResult); @@ -158,8 +192,7 @@ public class BanCommandGroup : CommandGroup { return (Result)await _feedbackService.SendContextualEmbedAsync(alreadyBuilt, ct: CancellationToken); } - Result responseEmbed; - + // Needed to get the tag and avatar var userResult = await _userApi.GetUserAsync(userId.Value, CancellationToken); if (!userResult.IsDefined(out var user)) return Result.FromError(userResult); @@ -170,7 +203,7 @@ public class BanCommandGroup : CommandGroup { if (!unbanResult.IsSuccess) return Result.FromError(unbanResult.Error); - responseEmbed = new EmbedBuilder().WithSmallTitle( + var responseEmbed = new EmbedBuilder().WithSmallTitle( string.Format(Messages.UserUnbanned, target.GetTag()), target) .WithColour(ColorsList.Green).Build(); @@ -187,6 +220,8 @@ public class BanCommandGroup : CommandGroup { return Result.FromError(logEmbed); var builtArray = new[] { logBuilt }; + + // Not awaiting to reduce response time if (cfg.PrivateFeedbackChannel != channelId.Value) _ = _channelApi.CreateMessageAsync( cfg.PrivateFeedbackChannel.ToDiscordSnowflake(), embeds: builtArray, diff --git a/Commands/ErrorLoggingPostExecutionEvent.cs b/Commands/ErrorLoggingPostExecutionEvent.cs index 65604bd..a85f8a7 100644 --- a/Commands/ErrorLoggingPostExecutionEvent.cs +++ b/Commands/ErrorLoggingPostExecutionEvent.cs @@ -7,6 +7,9 @@ using Remora.Results; namespace Boyfriend.Commands; +/// +/// Handles error logging for slash command groups. +/// public class ErrorLoggingPostExecutionEvent : IPostExecutionEvent { private readonly ILogger _logger; @@ -14,6 +17,14 @@ public class ErrorLoggingPostExecutionEvent : IPostExecutionEvent { _logger = logger; } + /// + /// Logs a warning using the injected if the has not + /// succeeded. + /// + /// The context of the slash command. Unused. + /// The result whose success is checked. + /// The cancellation token for this operation. Unused. + /// A result which has succeeded. public Task AfterExecutionAsync( ICommandContext context, IResult commandResult, CancellationToken ct = default) { if (!commandResult.IsSuccess) diff --git a/Data/GuildConfiguration.cs b/Data/GuildConfiguration.cs index 10a1553..61111df 100644 --- a/Data/GuildConfiguration.cs +++ b/Data/GuildConfiguration.cs @@ -1,8 +1,19 @@ using System.Globalization; +using Remora.Discord.API.Abstractions.Objects; namespace Boyfriend.Data; +/// +/// Stores per-guild settings that can be set by a member +/// with using the /settings command +/// public class GuildConfiguration { + /// + /// Represents a scheduled event notification receiver. + /// + /// + /// Used to selectively mention guild members when a scheduled event has started or is about to start. + /// public enum NotificationReceiver { Interested, Role @@ -14,22 +25,62 @@ public class GuildConfiguration { { "mctaylors-ru", new CultureInfo("tt-RU") } }; - public string Language { get; set; } = "en"; - public string WelcomeMessage { get; set; } = "default"; - public bool ReceiveStartupMessages { get; set; } - public bool RemoveRolesOnMute { get; set; } - public bool ReturnRolesOnRejoin { get; set; } - public bool AutoStartEvents { get; set; } - public ulong PublicFeedbackChannel { get; set; } - public ulong PrivateFeedbackChannel { get; set; } - public ulong EventNotificationChannel { get; set; } - public ulong StarterRole { get; set; } - public ulong MuteRole { get; set; } - public ulong EventNotificationRole { get; set; } + public string Language { get; set; } = "en"; + /// + /// Controls what message should be sent in when a new member joins the server. + /// + /// + /// + /// No message will be sent if set to "off", "disable" or "disabled". + /// will be sent if set to "default" or "reset" + /// + /// + /// + public string WelcomeMessage { get; set; } = "default"; + + /// + /// Controls whether or not the message should be sent + /// in on startup. + /// + /// + public bool ReceiveStartupMessages { get; set; } + + public bool RemoveRolesOnMute { get; set; } + + /// + /// Controls whether or not a guild member's roles are returned if he/she leaves and then joins back. + /// + /// Roles will not be returned if the member left the guild because of /ban or /kick. + public bool ReturnRolesOnRejoin { get; set; } + + public bool AutoStartEvents { get; set; } + + /// + /// Controls what channel should all public messages be sent to. + /// + public ulong PublicFeedbackChannel { get; set; } + + /// + /// Controls what channel should all private, moderator-only messages be sent to. + /// + public ulong PrivateFeedbackChannel { get; set; } + + public ulong EventNotificationChannel { get; set; } + public ulong DefaultRole { get; set; } + public ulong MuteRole { get; set; } + public ulong EventNotificationRole { get; set; } + + /// + /// Controls what guild members should be mentioned when a scheduled event has started or is about to start. + /// + /// public List EventStartedReceivers { get; set; } = new() { NotificationReceiver.Interested, NotificationReceiver.Role }; + /// + /// Controls the amount of time before a scheduled event to send a reminder in . + /// public TimeSpan EventEarlyNotificationOffset { get; set; } = TimeSpan.Zero; public CultureInfo Culture => CultureInfoCache[Language]; diff --git a/Data/GuildData.cs b/Data/GuildData.cs index 0b5495a..37aa958 100644 --- a/Data/GuildData.cs +++ b/Data/GuildData.cs @@ -2,12 +2,16 @@ using System.Globalization; namespace Boyfriend.Data; +/// +/// Stores information about a guild. This information is not accessible via the Discord API. +/// +/// This information is stored on disk as a JSON file. public class GuildData { public readonly GuildConfiguration Configuration; - public readonly string ConfigurationPath; + public readonly string ConfigurationPath; public readonly Dictionary ScheduledEvents; - public readonly string ScheduledEventsPath; + public readonly string ScheduledEventsPath; public GuildData( GuildConfiguration configuration, string configurationPath, diff --git a/Data/ScheduledEventData.cs b/Data/ScheduledEventData.cs index 5ef9393..41cb449 100644 --- a/Data/ScheduledEventData.cs +++ b/Data/ScheduledEventData.cs @@ -2,8 +2,12 @@ using Remora.Discord.API.Abstractions.Objects; namespace Boyfriend.Data; +/// +/// Stores information about scheduled events. This information is not provided by the Discord API. +/// +/// This information is stored on disk as a JSON file. public class ScheduledEventData { - public DateTimeOffset? ActualStartTime; + public DateTimeOffset? ActualStartTime; public GuildScheduledEventStatus Status; public ScheduledEventData(GuildScheduledEventStatus status) { diff --git a/EventResponders.cs b/EventResponders.cs index 66be8f2..689843a 100644 --- a/EventResponders.cs +++ b/EventResponders.cs @@ -21,11 +21,15 @@ using Remora.Results; namespace Boyfriend; +/// +/// Handles sending a message to a guild that has just initialized if that guild +/// has enabled +/// public class GuildCreateResponder : IResponder { - private readonly IDiscordRestChannelAPI _channelApi; - private readonly GuildDataService _dataService; + private readonly IDiscordRestChannelAPI _channelApi; + private readonly GuildDataService _dataService; private readonly ILogger _logger; - private readonly IDiscordRestUserAPI _userApi; + private readonly IDiscordRestUserAPI _userApi; public GuildCreateResponder( IDiscordRestChannelAPI channelApi, GuildDataService dataService, IDiscordRestUserAPI userApi, @@ -37,7 +41,7 @@ public class GuildCreateResponder : IResponder { } public async Task RespondAsync(IGuildCreate gatewayEvent, CancellationToken ct = default) { - if (!gatewayEvent.Guild.IsT0) return Result.FromSuccess(); // is IAvailableGuild + if (!gatewayEvent.Guild.IsT0) return Result.FromSuccess(); // Guild isn't IAvailableGuild var guild = gatewayEvent.Guild.AsT0; _logger.LogInformation("Joined guild \"{Name}\"", guild.Name); @@ -68,11 +72,15 @@ public class GuildCreateResponder : IResponder { } } +/// +/// Handles logging the contents of a deleted message and the user who deleted the message +/// to a guild's if one is set. +/// public class MessageDeletedResponder : IResponder { private readonly IDiscordRestAuditLogAPI _auditLogApi; - private readonly IDiscordRestChannelAPI _channelApi; - private readonly GuildDataService _dataService; - private readonly IDiscordRestUserAPI _userApi; + private readonly IDiscordRestChannelAPI _channelApi; + private readonly GuildDataService _dataService; + private readonly IDiscordRestUserAPI _userApi; public MessageDeletedResponder( IDiscordRestAuditLogAPI auditLogApi, IDiscordRestChannelAPI channelApi, @@ -129,11 +137,15 @@ public class MessageDeletedResponder : IResponder { } } +/// +/// Handles logging the difference between an edited message's old and new content +/// to a guild's if one is set. +/// public class MessageEditedResponder : IResponder { - private readonly CacheService _cacheService; + private readonly CacheService _cacheService; private readonly IDiscordRestChannelAPI _channelApi; - private readonly GuildDataService _dataService; - private readonly IDiscordRestUserAPI _userApi; + private readonly GuildDataService _dataService; + private readonly IDiscordRestUserAPI _userApi; public MessageEditedResponder( CacheService cacheService, IDiscordRestChannelAPI channelApi, GuildDataService dataService, @@ -153,7 +165,7 @@ public class MessageEditedResponder : IResponder { if (!gatewayEvent.Content.IsDefined(out var newContent)) return Result.FromSuccess(); if (!gatewayEvent.EditedTimestamp.IsDefined(out var timestamp)) - return Result.FromSuccess(); + return Result.FromSuccess(); // The message wasn't actually edited if (!gatewayEvent.ChannelID.IsDefined(out var channelId)) return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.ChannelID))); @@ -199,10 +211,14 @@ public class MessageEditedResponder : IResponder { } } +/// +/// Handles sending a guild's if one is set. +/// +/// public class GuildMemberAddResponder : IResponder { private readonly IDiscordRestChannelAPI _channelApi; - private readonly GuildDataService _dataService; - private readonly IDiscordRestGuildAPI _guildApi; + private readonly GuildDataService _dataService; + private readonly IDiscordRestGuildAPI _guildApi; public GuildMemberAddResponder( IDiscordRestChannelAPI channelApi, GuildDataService dataService, IDiscordRestGuildAPI guildApi) { @@ -243,10 +259,16 @@ public class GuildMemberAddResponder : IResponder { } } +/// +/// Handles sending a notification, mentioning the if one is +/// set, +/// when a scheduled event is created +/// in a guild's if one is set. +/// public class GuildScheduledEventCreateResponder : IResponder { private readonly IDiscordRestChannelAPI _channelApi; - private readonly GuildDataService _dataService; - private readonly IDiscordRestUserAPI _userApi; + private readonly GuildDataService _dataService; + private readonly IDiscordRestUserAPI _userApi; public GuildScheduledEventCreateResponder( IDiscordRestChannelAPI channelApi, GuildDataService dataService, @@ -339,9 +361,15 @@ public class GuildScheduledEventCreateResponder : IResponder +/// Handles sending a notification, mentioning the if one is +/// set, +/// when a scheduled event has started or completed +/// in a guild's if one is set. +/// public class GuildScheduledEventUpdateResponder : IResponder { - private readonly IDiscordRestChannelAPI _channelApi; - private readonly GuildDataService _dataService; + private readonly IDiscordRestChannelAPI _channelApi; + private readonly GuildDataService _dataService; private readonly IDiscordRestGuildScheduledEventAPI _eventApi; public GuildScheduledEventUpdateResponder( @@ -353,10 +381,16 @@ public class GuildScheduledEventUpdateResponder : IResponder RespondAsync(IGuildScheduledEventUpdate gatewayEvent, CancellationToken ct = default) { var guildData = await _dataService.GetData(gatewayEvent.GuildID, ct); - if (gatewayEvent.Status == guildData.ScheduledEvents[gatewayEvent.ID.Value].Status - || guildData.Configuration.EventNotificationChannel is 0) return Result.FromSuccess(); + if (guildData.Configuration.EventNotificationChannel is 0) + return Result.FromSuccess(); + if (!guildData.ScheduledEvents.TryGetValue(gatewayEvent.ID.Value, out var data)) { + guildData.ScheduledEvents.Add(gatewayEvent.ID.Value, new ScheduledEventData(gatewayEvent.Status)); + } else { + if (gatewayEvent.Status == data.Status) + return Result.FromSuccess(); - guildData.ScheduledEvents[gatewayEvent.ID.Value].Status = gatewayEvent.Status; + guildData.ScheduledEvents[gatewayEvent.ID.Value].Status = gatewayEvent.Status; + } var embed = new EmbedBuilder(); StringBuilder? content = null; @@ -442,11 +476,15 @@ public class GuildScheduledEventUpdateResponder : IResponder { +/// +/// Handles sending a notification when a scheduled event has been cancelled +/// in a guild's if one is set. +/// +public class GuildScheduledEventDeleteResponder : IResponder { private readonly IDiscordRestChannelAPI _channelApi; - private readonly GuildDataService _dataService; + private readonly GuildDataService _dataService; - public GuildScheduledEventResponder(IDiscordRestChannelAPI channelApi, GuildDataService dataService) { + public GuildScheduledEventDeleteResponder(IDiscordRestChannelAPI channelApi, GuildDataService dataService) { _channelApi = channelApi; _dataService = dataService; } diff --git a/Extensions.cs b/Extensions.cs index 8e4f0eb..7c7c5d4 100644 --- a/Extensions.cs +++ b/Extensions.cs @@ -10,6 +10,12 @@ using Remora.Rest.Core; namespace Boyfriend; public static class Extensions { + /// + /// Adds a footer with the 's avatar and tag (username#0000). + /// + /// The builder to add the footer to. + /// The user whose tag and avatar to add. + /// The builder with the added footer. public static EmbedBuilder WithUserFooter(this EmbedBuilder builder, IUser user) { var avatarUrlResult = CDN.GetUserAvatarUrl(user, imageSize: 256); var avatarUrl = avatarUrlResult.IsSuccess @@ -19,6 +25,12 @@ public static class Extensions { return builder.WithFooter(new EmbedFooter(user.GetTag(), avatarUrl)); } + /// + /// Adds a footer representing that an action was performed by a . + /// + /// The builder to add the footer to. + /// The user that performed the action whose tag and avatar to use. + /// The builder with the added footer. public static EmbedBuilder WithActionFooter(this EmbedBuilder builder, IUser user) { var avatarUrlResult = CDN.GetUserAvatarUrl(user, imageSize: 256); var avatarUrl = avatarUrlResult.IsSuccess @@ -29,6 +41,14 @@ public static class Extensions { new EmbedFooter($"{Messages.IssuedBy}:\n{user.GetTag()}", avatarUrl)); } + /// + /// Adds a title using the author field, making it smaller than using the title field. + /// + /// The builder to add the small title to. + /// The text of the small title. + /// The user whose avatar to use in the small title. + /// The URL that will be opened if a user clicks on the small title. + /// The builder with the added small title in the author field. public static EmbedBuilder WithSmallTitle( this EmbedBuilder builder, string text, IUser? avatarSource = null, string? url = default) { Uri? avatarUrl = null; @@ -44,6 +64,12 @@ public static class Extensions { return builder; } + /// + /// Adds a footer representing that the action was performed in the . + /// + /// The builder to add the footer to. + /// The guild whose name and icon to use. + /// The builder with the added footer. public static EmbedBuilder WithGuildFooter(this EmbedBuilder builder, IGuild guild) { var iconUrlResult = CDN.GetGuildIconUrl(guild, imageSize: 256); var iconUrl = iconUrlResult.IsSuccess @@ -53,6 +79,13 @@ public static class Extensions { return builder.WithFooter(new EmbedFooter(guild.Name, iconUrl)); } + /// + /// Adds a scheduled event's cover image. + /// + /// The builder to add the image to. + /// The ID of the scheduled event whose image to use. + /// The Optional containing the image hash. + /// The builder with the added cover image. public static EmbedBuilder WithEventCover( this EmbedBuilder builder, Snowflake eventId, Optional imageHashOptional) { if (!imageHashOptional.IsDefined(out var imageHash)) return builder; @@ -61,6 +94,12 @@ public static class Extensions { return iconUrlResult.IsDefined(out var iconUrl) ? builder.WithImageUrl(iconUrl.AbsoluteUri) : builder; } + /// + /// Sanitizes a string for use in by inserting zero-width spaces in between + /// symbols used to format the string with block code. + /// + /// The string to sanitize. + /// The sanitized string that can be safely used in . public static string SanitizeForBlockCode(this string s) { return s.Replace("```", "​`​`​`​"); } @@ -82,7 +121,6 @@ public static class Extensions { return $"{user.Username}#{user.Discriminator:0000}"; } - public static Snowflake ToDiscordSnowflake(this ulong id) { return DiscordSnowflake.New(id); } diff --git a/InteractionResponders.cs b/InteractionResponders.cs index e554668..6d2b729 100644 --- a/InteractionResponders.cs +++ b/InteractionResponders.cs @@ -9,6 +9,9 @@ using Remora.Results; namespace Boyfriend; +/// +/// Handles responding to various interactions. +/// public class InteractionResponders : InteractionGroup { private readonly FeedbackService _feedbackService; @@ -16,6 +19,11 @@ public class InteractionResponders : InteractionGroup { _feedbackService = feedbackService; } + /// + /// A button that will output an ephemeral embed containing the information about a scheduled event. + /// + /// The ID of the guild and scheduled event, encoded as "guildId:eventId". + /// A feedback sending result which may or may not have succeeded. [Button("scheduled-event-details")] public async Task OnStatefulButtonClicked(string? state = null) { if (state is null) return Result.FromError(new ArgumentNullError(nameof(state))); diff --git a/Messages.Designer.cs b/Messages.Designer.cs index b3ef2bb..f44d07c 100644 --- a/Messages.Designer.cs +++ b/Messages.Designer.cs @@ -705,9 +705,9 @@ namespace Boyfriend { } } - internal static string SettingsStarterRole { + internal static string SettingsDefaultRole { get { - return ResourceManager.GetString("SettingsStarterRole", resourceCulture); + return ResourceManager.GetString("SettingsDefaultRole", resourceCulture); } } diff --git a/Messages.resx b/Messages.resx index cce2611..a851ca0 100644 --- a/Messages.resx +++ b/Messages.resx @@ -435,9 +435,9 @@ I could not find this user in any guild I'm a member of! Check if the ID is correct and that the user was on this server no longer than 30 days ago - - Starter role - + + Default role + Adds a reminder diff --git a/Messages.ru.resx b/Messages.ru.resx index 3d486ec..b398e0d 100644 --- a/Messages.ru.resx +++ b/Messages.ru.resx @@ -435,9 +435,9 @@ Я не смог найти этого пользователя ни в одном из серверов, в которых я есть. Проверь правильность ID и нахождение пользователя на этом сервере максимум 30 дней назад - - Начальная роль - + + Общая роль + Добавляет напоминание diff --git a/Messages.tt-ru.resx b/Messages.tt-ru.resx index 77f724c..3c07256 100644 --- a/Messages.tt-ru.resx +++ b/Messages.tt-ru.resx @@ -435,9 +435,9 @@ у нас такого шизоида нету, проверь, валиден ли ID уважаемого (я забываю о шизоидах если они ливнули минимум месяц назад) - - базовое звание - + + дефолтное звание + крафтит напоминалку diff --git a/Services/Data/GuildDataService.cs b/Services/Data/GuildDataService.cs index 2011fca..3de57b1 100644 --- a/Services/Data/GuildDataService.cs +++ b/Services/Data/GuildDataService.cs @@ -5,6 +5,9 @@ using Remora.Rest.Core; namespace Boyfriend.Services.Data; +/// +/// Handles saving, loading, initializing and providing . +/// public class GuildDataService : IHostedService { private readonly Dictionary _datas = new(); diff --git a/Services/UtilityService.cs b/Services/UtilityService.cs index b035306..7ce6da6 100644 --- a/Services/UtilityService.cs +++ b/Services/UtilityService.cs @@ -5,6 +5,10 @@ using Remora.Results; namespace Boyfriend.Services; +/// +/// Provides utility methods that cannot be transformed to extension methods because they require usage +/// of some Discord APIs. +/// public class UtilityService : IHostedService { private readonly IDiscordRestGuildAPI _guildApi; private readonly IDiscordRestUserAPI _userApi; @@ -22,6 +26,24 @@ public class UtilityService : IHostedService { return Task.CompletedTask; } + /// + /// Checks whether or not a member can interact with another member + /// + /// The ID of the guild in which an operation is being performed. + /// The executor of the operation. + /// The target of the operation. + /// The operation. + /// The cancellation token for this operation. + /// + /// + /// A result which has succeeded with a null string if the member can interact with the target. + /// + /// A result which has succeeded with a non-null string containing the error message if the member cannot + /// interact with the target. + /// + /// A result which has failed if an error occurred during the execution of this method. + /// + /// public async Task> CheckInteractionsAsync( Snowflake guildId, Snowflake interacterId, Snowflake targetId, string action, CancellationToken ct = default) { if (interacterId == targetId)