diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d7e30e..870ada6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.4.0] - 2023-07-23 + +### Added + +- Add new ACCEPTED suggestion status. + +### Changed + +- `/suggestion implement` and `/suggestion reject` combined to `/suggestion setstatus`. + ## [1.3.2] - 2023-07-22 ### Added diff --git a/SuggestionBot/Commands/SuggestionCommand.Reject.cs b/SuggestionBot/Commands/SuggestionCommand.Reject.cs deleted file mode 100644 index a6587e5..0000000 --- a/SuggestionBot/Commands/SuggestionCommand.Reject.cs +++ /dev/null @@ -1,43 +0,0 @@ -using DSharpPlus.Entities; -using DSharpPlus.SlashCommands; -using SuggestionBot.AutocompleteProviders; -using SuggestionBot.Data; - -namespace SuggestionBot.Commands; - -internal sealed partial class SuggestionCommand -{ - [SlashCommand("reject", "Rejects a suggestion.", false)] - public async Task RejectAsync(InteractionContext context, - [Option("suggestion", "The suggestion to reject."), Autocomplete(typeof(SuggestionAutocompleteProvider))] - string query) - { - var response = new DiscordInteractionResponseBuilder(); - - if (!TryGetSuggestion(context.Guild, query, out Suggestion? suggestion)) - { - response.AsEphemeral(); - response.AddEmbed(CreateNotFoundEmbed(query)); - await context.CreateResponseAsync(ResponseType, response).ConfigureAwait(false); - return; - } - - var embed = new DiscordEmbedBuilder(); - if (_suggestionService.Reject(suggestion, context.Member)) - { - embed.WithColor(DiscordColor.Orange); - embed.WithTitle("Suggestion Rejected"); - embed.WithDescription($"The suggestion with the ID {suggestion.Id} has been marked as REJECTED."); - } - else - { - embed.WithColor(DiscordColor.Orange); - embed.WithTitle("Suggestion Unchanged"); - embed.WithDescription($"The suggestion with the ID {suggestion.Id} was already rejected. " + - "No changes were made."); - } - - response.AddEmbed(embed); - await context.CreateResponseAsync(ResponseType, response).ConfigureAwait(false); - } -} diff --git a/SuggestionBot/Commands/SuggestionCommand.Implement.cs b/SuggestionBot/Commands/SuggestionCommand.SetStatus.cs similarity index 61% rename from SuggestionBot/Commands/SuggestionCommand.Implement.cs rename to SuggestionBot/Commands/SuggestionCommand.SetStatus.cs index df0383e..e4e720c 100644 --- a/SuggestionBot/Commands/SuggestionCommand.Implement.cs +++ b/SuggestionBot/Commands/SuggestionCommand.SetStatus.cs @@ -1,5 +1,6 @@ using DSharpPlus.Entities; using DSharpPlus.SlashCommands; +using Humanizer; using SuggestionBot.AutocompleteProviders; using SuggestionBot.Data; @@ -7,10 +8,13 @@ namespace SuggestionBot.Commands; internal sealed partial class SuggestionCommand { - [SlashCommand("implement", "Implements a suggestion.", false)] - public async Task ImplementAsync(InteractionContext context, - [Option("suggestion", "The suggestion to implement."), Autocomplete(typeof(SuggestionAutocompleteProvider))] - string query) + [SlashCommand("setstatus", "Sets a new status for a suggestion.", false)] + public async Task SetStatusAsync(InteractionContext context, + [Option("suggestion", "The suggestion whose status to change.")] + [Autocomplete(typeof(SuggestionAutocompleteProvider))] + string query, + [Option("status", "The new status of the suggestion.")] + SuggestionStatus status) { var response = new DiscordInteractionResponseBuilder(); @@ -23,17 +27,19 @@ public async Task ImplementAsync(InteractionContext context, } var embed = new DiscordEmbedBuilder(); - if (_suggestionService.Implement(suggestion, context.Member)) + string humanizedStatus = status.Humanize(LetterCasing.AllCaps); + + if (_suggestionService.SetStatus(suggestion, status, context.Member)) { embed.WithColor(DiscordColor.Orange); - embed.WithTitle("Suggestion Implemented"); - embed.WithDescription($"The suggestion with the ID {suggestion.Id} has been marked as IMPLEMENTED."); + embed.WithTitle("Suggestion Status Changed"); + embed.WithDescription($"The suggestion with the ID {suggestion.Id} has been marked as {humanizedStatus}."); } else { embed.WithColor(DiscordColor.Orange); embed.WithTitle("Suggestion Unchanged"); - embed.WithDescription($"The suggestion with the ID {suggestion.Id} was already implemented. " + + embed.WithDescription($"The suggestion with the ID {suggestion.Id} was already {humanizedStatus}. " + "No changes were made."); } diff --git a/SuggestionBot/Configuration/GuildConfiguration.cs b/SuggestionBot/Configuration/GuildConfiguration.cs index 3c93b19..4c1a62c 100644 --- a/SuggestionBot/Configuration/GuildConfiguration.cs +++ b/SuggestionBot/Configuration/GuildConfiguration.cs @@ -5,6 +5,12 @@ /// public sealed class GuildConfiguration { + /// + /// Gets or sets the embed color for accepted suggestions. + /// + /// The embed color for accepted suggestions. + public int AcceptedColor { get; set; } = 0x00FF00; + /// /// Gets or sets the cooldown for posting suggestions. /// diff --git a/SuggestionBot/Data/SuggestionStatus.cs b/SuggestionBot/Data/SuggestionStatus.cs index 8ce56e0..9dbfd20 100644 --- a/SuggestionBot/Data/SuggestionStatus.cs +++ b/SuggestionBot/Data/SuggestionStatus.cs @@ -7,5 +7,6 @@ public enum SuggestionStatus { Suggested, Rejected, - Implemented + Implemented, + Accepted } diff --git a/SuggestionBot/Services/SuggestionService.cs b/SuggestionBot/Services/SuggestionService.cs index 7f7ddae..ceae1f6 100644 --- a/SuggestionBot/Services/SuggestionService.cs +++ b/SuggestionBot/Services/SuggestionService.cs @@ -74,6 +74,7 @@ public DiscordEmbed CreatePrivateEmbed(Suggestion suggestion) SuggestionStatus.Suggested => "🗳️", SuggestionStatus.Rejected => "❌", SuggestionStatus.Implemented => "✅", + SuggestionStatus.Accepted => "✅", _ => throw new ArgumentOutOfRangeException(nameof(suggestion), suggestion.Status, null) }; @@ -89,6 +90,7 @@ public DiscordEmbed CreatePrivateEmbed(Suggestion suggestion) SuggestionStatus.Suggested => configuration.SuggestedColor, SuggestionStatus.Rejected => configuration.RejectedColor, SuggestionStatus.Implemented => configuration.ImplementedColor, + SuggestionStatus.Accepted => configuration.AcceptedColor, _ => throw new ArgumentOutOfRangeException(nameof(suggestion), suggestion.Status, null) }); @@ -136,6 +138,7 @@ public DiscordEmbed CreatePublicEmbed(Suggestion suggestion) SuggestionStatus.Suggested => "🗳️", SuggestionStatus.Rejected => "❌", SuggestionStatus.Implemented => "✅", + SuggestionStatus.Accepted => "✅", _ => throw new ArgumentOutOfRangeException(nameof(suggestion), suggestion.Status, null) }; @@ -152,6 +155,7 @@ public DiscordEmbed CreatePublicEmbed(Suggestion suggestion) SuggestionStatus.Suggested => configuration.SuggestedColor, SuggestionStatus.Rejected => configuration.RejectedColor, SuggestionStatus.Implemented => configuration.ImplementedColor, + SuggestionStatus.Accepted => configuration.AcceptedColor, _ => throw new ArgumentOutOfRangeException(nameof(suggestion), suggestion.Status, null) }); @@ -317,42 +321,6 @@ public Uri GetSuggestionLink(Suggestion suggestion) return new Uri($"https://discord.com/channels/{guildId}/{configuration?.SuggestionChannel}/{messageId}"); } - /// - /// Marks a suggestion as implemented, and optionally updates the remarks for the implementation. - /// - /// The suggestion to update. - /// The staff member who implemented the suggestion. - /// if the status was updated; otherwise, . - /// - /// is . - /// -or- - /// is . - /// - public bool Implement(Suggestion suggestion, DiscordMember staffMember) - { - if (suggestion is null) - { - throw new ArgumentNullException(nameof(suggestion)); - } - - if (staffMember is null) - { - throw new ArgumentNullException(nameof(staffMember)); - } - - if (!SetStatus(suggestion, SuggestionStatus.Implemented, staffMember)) - { - return false; - } - - _logger.LogInformation("{StaffMember} marked suggestion {Id} as IMPLEMENTED", staffMember, suggestion.Id); - - using SuggestionContext context = _contextFactory.CreateDbContext(); - context.Suggestions.Update(suggestion); - context.SaveChanges(); - return true; - } - /// /// Posts a suggestion to the suggestion channel of the guild in which it was made. /// @@ -396,42 +364,6 @@ public bool Implement(Suggestion suggestion, DiscordMember staffMember) return message; } - /// - /// Marks a suggestion as rejected, and updates the reason for the rejection if one is provided. - /// - /// The suggestion to update. - /// The staff member who rejected the suggestion. - /// if the status was updated; otherwise, . - /// - /// is . - /// -or- - /// is . - /// - public bool Reject(Suggestion suggestion, DiscordMember staffMember) - { - if (suggestion is null) - { - throw new ArgumentNullException(nameof(suggestion)); - } - - if (staffMember is null) - { - throw new ArgumentNullException(nameof(staffMember)); - } - - if (!SetStatus(suggestion, SuggestionStatus.Rejected, staffMember)) - { - return false; - } - - _logger.LogInformation("{StaffMember} marked suggestion {Id} as REJECTED", staffMember, suggestion.Id); - - using SuggestionContext context = _contextFactory.CreateDbContext(); - context.Suggestions.Update(suggestion); - context.SaveChanges(); - return true; - } - /// /// Sets the message of a suggestion. /// @@ -503,6 +435,9 @@ public bool SetStatus(Suggestion suggestion, SuggestionStatus status, DiscordMem context.Suggestions.Update(suggestion); context.SaveChanges(); + _logger.LogInformation("{StaffMember} marked suggestion {Id} as {Status}", staffMember, suggestion.Id, + humanizedStatus); + _ = UpdateSuggestionAsync(suggestion); return true; } diff --git a/USAGE.md b/USAGE.md index 9f6527e..4af15da 100644 --- a/USAGE.md +++ b/USAGE.md @@ -38,21 +38,14 @@ Allow a user to send suggestions again. ## Implementing and Rejecting Suggestions -### `/suggestion implement` +### `/suggestion setstatus` -Mark a suggestion as implemented. +Change the status of a suggestion -| Parameter | Required | Type | Description | -|:-----------|:---------|:-------------------------|:-----------------------------| -| suggestion | ✅ Yes | Suggestion or Message ID | The suggestion to implement. | - -### `/suggestion reject` - -Mark a suggestion as rejected. - -| Parameter | Required | Type | Description | -|:-----------|:---------|:-------------------------|:--------------------------| -| suggestion | ✅ Yes | Suggestion or Message ID | The suggestion to reject. | +| Parameter | Required | Type | Description | +|:-----------|:---------|:-------------------------|:---------------------------------------| +| suggestion | ✅ Yes | Suggestion or Message ID | The suggestion whose status to change. | +| status | ✅ Yes | SuggestionStatus | The new status of the suggestion. | # Ephemeral responses