From 374804f616573d05c4c44884135029c7036ce81f Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:28:54 -0500 Subject: [PATCH 01/61] Merge SimplyJPK's TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 143 +++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 DiscordBot/Services/Tips/TipService.cs diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs new file mode 100644 index 00000000..8c39e285 --- /dev/null +++ b/DiscordBot/Services/Tips/TipService.cs @@ -0,0 +1,143 @@ +using System.Collections.Concurrent; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Text.RegularExpressions; +using Discord; +using Discord.WebSocket; +using DiscordBot.Services.Tips.Components; +using DiscordBot.Settings; +using Newtonsoft.Json; + +namespace DiscordBot.Services.Tips; + +public class TipService +{ + private const string ServiceName = "TipService"; + + private readonly BotSettings _settings; + private readonly ILoggingService _loggingService; + private readonly string _imageDirectory; + + private ConcurrentDictionary> _tips = new(); + private bool _isRunning = false; + + public TipService(BotSettings settings, ILoggingService loggingService) + { + _settings = settings; + _loggingService = loggingService; + + if (string.IsNullOrEmpty(_settings.TipImageDirectory)) + { + _loggingService.LogAction($"[{ServiceName}] TipImageDirectory not set, service will not run.", ExtendedLogSeverity.Warning); + _isRunning = false; + return; + } + + _imageDirectory = Path.Combine(Directory.GetCurrentDirectory(), _settings.TipImageDirectory); + + Initialize(); + } + + private void Initialize() + { + if (_isRunning) return; + + if (!Directory.Exists(_imageDirectory)) + { + Directory.CreateDirectory(_imageDirectory); + File.WriteAllText(Path.Combine(_imageDirectory, "tips.json"), "{}"); + } + else + { + var directorySize = new DirectoryInfo(_imageDirectory).EnumerateFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length); + if (directorySize > _settings.TipMaxDirectoryFileSize) + { + _loggingService.LogAction($"[{ServiceName}] Tip directory size is {directorySize / 1024 / 1024} MB, exceeding the limit of {_settings.TipMaxDirectoryFileSize / 1024 / 1024} MB, no additional content will be added during this session.", ExtendedLogSeverity.Warning); + } + else + { + _loggingService.LogAction($"[{ServiceName}] Tip directory size is {directorySize / 1024 / 1024} MB, within the limit of {_settings.TipMaxDirectoryFileSize / 1024 / 1024} MB.", ExtendedLogSeverity.Info); + _loggingService.LogAction($"[{ServiceName}] Tip directory contains {new DirectoryInfo(_imageDirectory).EnumerateFiles("*.*", SearchOption.AllDirectories).Count()} files.", + ExtendedLogSeverity.Info); + } + + var jsonPath = Path.Combine(_imageDirectory, "tips.json"); + if (File.Exists(jsonPath)) + { + var json = File.ReadAllText(jsonPath); + _tips = JsonConvert.DeserializeObject>>(json); + } + } + + _isRunning = true; + } + + public async Task AddTip(IUserMessage message, string keywords, string content) + { + var keywordList = keywords.Split(',').Select(k => k.Trim()).ToList(); + var imagePaths = new List(); + + foreach (var attachment in message.Attachments) + { + if (!attachment.Filename.EndsWith(".png") && !attachment.Filename.EndsWith(".webp") && !attachment.Filename.EndsWith(".jpg")) continue; + var newFileName = Guid.NewGuid().ToString() + attachment.Filename.Substring(attachment.Filename.LastIndexOf('.')); + var filePath = Path.Combine(_imageDirectory, newFileName); + if (attachment.Size > _settings.TipMaxImageFileSize) + { + continue; + } + + using var client = new HttpClient(); + await using var stream = await client.GetStreamAsync(attachment.Url); + await using var file = File.Create(filePath); + await stream.CopyToAsync(file); + + imagePaths.Add(newFileName); + } + + var tip = new Tip + { + Content = content, + Keywords = keywordList, + ImagePaths = imagePaths + }; + + foreach (var keyword in keywordList) + { + _tips.AddOrUpdate(keyword, new List { tip }, (key, list) => + { + list.Add(tip); + return list; + }); + } + + // In same folder, we save json files + var jsonPath = Path.Combine(_imageDirectory, "tips.json"); + await File.WriteAllTextAsync(jsonPath, JsonConvert.SerializeObject(_tips)); + + await _loggingService.LogAction($"[{ServiceName}] Added tip from {message.Author.Username} with keywords {string.Join(", ", keywordList)}.", ExtendedLogSeverity.Info); + + // Send a confirmation message + if (message.Channel is SocketTextChannel textChannel) + { + var builder = new EmbedBuilder() + .WithTitle("Tip Added") + .WithDescription($"Your tip has been added with the keywords `{string.Join(", ", keywordList)}`.") + .WithColor(Color.Green); + + // TODO: (James) Attach the images if they exist? + + await textChannel.SendMessageAsync(embed: builder.Build()); + } + } + + public List GetTips(string keyword) + { + var regex = new Regex(keyword, RegexOptions.IgnoreCase); + return _tips.Where(kvp => kvp.Key.Split(',').Any(k => regex.IsMatch(k))) + .SelectMany(kvp => kvp.Value) + .Distinct() + .ToList(); + } +} From 3cc02e4b6aa78ff9fdc3d0cb1a364887f55f2faa Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:30:25 -0500 Subject: [PATCH 02/61] Merge SimplyJPK's Tip.cs --- DiscordBot/Services/Tips/Components/Tip.cs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 DiscordBot/Services/Tips/Components/Tip.cs diff --git a/DiscordBot/Services/Tips/Components/Tip.cs b/DiscordBot/Services/Tips/Components/Tip.cs new file mode 100644 index 00000000..4b4fdb3a --- /dev/null +++ b/DiscordBot/Services/Tips/Components/Tip.cs @@ -0,0 +1,8 @@ +namespace DiscordBot.Services.Tips.Components; + +public class Tip +{ + public string Content { get; set; } + public List Keywords { get; set; } + public List ImagePaths { get; set; } +} From 46cd8c778d46f644d474b97fbf38b78158e6540a Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:32:37 -0500 Subject: [PATCH 03/61] Merge SimplyJPK's Program.cs --- DiscordBot/Program.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Program.cs b/DiscordBot/Program.cs index 08655ad2..11711cba 100644 --- a/DiscordBot/Program.cs +++ b/DiscordBot/Program.cs @@ -4,6 +4,7 @@ using Discord.WebSocket; using DiscordBot.Service; using DiscordBot.Services; +using DiscordBot.Services.Tips; using DiscordBot.Settings; using DiscordBot.Utils; using Microsoft.Extensions.DependencyInjection; @@ -104,6 +105,7 @@ private IServiceProvider ConfigureServices() => .AddSingleton() .AddSingleton() .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .BuildServiceProvider(); @@ -114,4 +116,4 @@ private static void DeserializeSettings() _rules = SerializeUtil.DeserializeFile(@"Settings/Rules.json"); _userSettings = SerializeUtil.DeserializeFile(@"Settings/UserSettings.json"); } -} \ No newline at end of file +} From 755f89e4d79815ba8405d402c4739a36aabd7ba7 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:37:32 -0500 Subject: [PATCH 04/61] Merge SimplyJPK's TipModule.cs --- DiscordBot/Modules/TipModule.cs | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 DiscordBot/Modules/TipModule.cs diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs new file mode 100644 index 00000000..cc4fc083 --- /dev/null +++ b/DiscordBot/Modules/TipModule.cs @@ -0,0 +1,90 @@ +using System.IO; +using Discord.Commands; +using DiscordBot.Attributes; +using DiscordBot.Services; +using DiscordBot.Services.Tips; +using DiscordBot.Settings; + +// ReSharper disable all UnusedMember.Local +namespace DiscordBot.Modules; + +public class TipModule : ModuleBase +{ + #region Dependency Injection + + public CommandHandlingService CommandHandlingService { get; set; } + public BotSettings Settings { get; set; } + public TipService TipService { get; set; } + + #endregion + + [Command("Tip")] + [Summary("Find and provide pre-authored tips (images or text) by their keywords.")] + public async Task Tip(string keywords) + { + var tips = TipService.GetTips(keywords); + if (tips.Count == 0) + { + await ReplyAsync("No tips for the keywords provided were found."); + return; + } + + var isAnyTextTips = tips.Any(tip => !string.IsNullOrEmpty(tip.Content)); + EmbedBuilder builder = new EmbedBuilder(); + if (isAnyTextTips) + { + // Loop through tips in order, have dot point list of the .Content property in an embed + builder + .WithTitle("Tip List") + .WithDescription("Here are the tips for your keywords:"); + foreach (var tip in tips) + { + builder.AddField(tip.Keywords.Count == 1 ? tip.Keywords[0] : "Multiple Keywords", tip.Content); + } + } + + var attachments = tips + .Where(tip => tip.ImagePaths != null && tip.ImagePaths.Any()) + .SelectMany(tip => tip.ImagePaths) + .Select(imagePath => new FileAttachment(Path.Combine(Settings.TipImageDirectory, imagePath))) + .ToList(); + + if (attachments.Count > 0) + { + if (isAnyTextTips) + { + await Context.Channel.SendFilesAsync(attachments, embed: builder.Build()); + } + else + { + await Context.Channel.SendFilesAsync(attachments); + } + } + else + { + await ReplyAsync(embed: builder.Build()); + } + } + + [Command("AddTip")] + [Summary("Add a tip to the database.")] + [RequireModerator] + public async Task AddTip(string keywords, string content = "") + { + await TipService.AddTip(Context.Message, keywords, content); + } + + #region CommandList + + [Summary("Does what you see now.")] + [Command("Ticket Help")] + public async Task TicketHelp() + { + foreach (var message in CommandHandlingService.GetCommandListMessages("TipModule", true, true, false)) + { + await ReplyAsync(message); + } + } + #endregion + +} From 29f9bdae69d37856924266c6d4e9416da4ff1a2f Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:57:13 -0500 Subject: [PATCH 05/61] Merge SimplyJPK's Tip Service Settings.cs --- DiscordBot/Settings/Deserialized/Settings.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Settings/Deserialized/Settings.cs b/DiscordBot/Settings/Deserialized/Settings.cs index f8d0d30e..342fe0cb 100644 --- a/DiscordBot/Settings/Deserialized/Settings.cs +++ b/DiscordBot/Settings/Deserialized/Settings.cs @@ -115,6 +115,16 @@ public class BotSettings #endregion // Recruitment Thread Tags #region Unity Help Threads + + #region Tips + + public string TipImageDirectory { get; set; } + + public int TipMaxImageFileSize { get; set; } = 1024 * 1024 * 10; // 10MB + // Unlikely, but we prevent exploitation by limiting the max directory size to avoid VPS disk space issues + public int TipMaxDirectoryFileSize { get; set; } = 1024 * 1024 * 1024; // 1GB + + #endregion // Tips public string TagUnitHelpResolvedTag { get; set; } @@ -191,4 +201,4 @@ public string GenerateFirstMessage(IUser author) } } -#endregion \ No newline at end of file +#endregion From 39e76390061ab2d69072ec9f91b89ee653b787a0 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 12:17:00 -0500 Subject: [PATCH 06/61] Update TipModule.cs Require moderator just to use !tip until released. Fix TipHelp command copy/paste mistake. --- DiscordBot/Modules/TipModule.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index cc4fc083..94862659 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -20,6 +20,7 @@ public class TipModule : ModuleBase [Command("Tip")] [Summary("Find and provide pre-authored tips (images or text) by their keywords.")] + /* for now */ [RequireModerator] public async Task Tip(string keywords) { var tips = TipService.GetTips(keywords); @@ -76,9 +77,9 @@ public async Task AddTip(string keywords, string content = "") #region CommandList - [Summary("Does what you see now.")] - [Command("Ticket Help")] - public async Task TicketHelp() + [Command("Tip Help")] + [Summary("Shows available tip commands.")] + public async Task TipHelp() { foreach (var message in CommandHandlingService.GetCommandListMessages("TipModule", true, true, false)) { From 75794f5e8809ada3614ccacf29518e8a88dee815 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:28:14 -0500 Subject: [PATCH 07/61] Error checking / validation in TipService.cs * break out rules for valid keywords, attachments * give error messages for invalid provided arguments * detect and ignore empty tips --- DiscordBot/Services/Tips/TipService.cs | 65 ++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 8c39e285..4a716013 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using System.Text.RegularExpressions; using System.IO; using System.Net; using System.Net.Http; @@ -21,7 +22,9 @@ public class TipService private ConcurrentDictionary> _tips = new(); private bool _isRunning = false; - + + private Regex keywordPattern = null; + public TipService(BotSettings settings, ILoggingService loggingService) { _settings = settings; @@ -73,14 +76,54 @@ private void Initialize() _isRunning = true; } + private bool IsValidTipKeyword(string keyword) + { + // start with ascii letter + // continue with ascii letters, digits, limited punctuation + // no whitespace, no commas + // + // valid examples: "dr.mendeleev" "f451" "wash_hands" "Poe's-Law" + // + if (keywordPattern == null) + keywordPattern = new Regex(@"^[a-z][a-z.0-9_'-]*$", RegexOptions.IgnoreCase); + + if (!keywordPattern.IsMatch(keyword)) + return false; + + return true; + } + + private bool IsValidTipAttachment(IAttachment attachment) + { + // Discord-friendly attachment image file formats only + // + if (attachment.Filename.EndsWith(".png")) return true; + if (attachment.Filename.EndsWith(".webp")) return true; + if (attachment.Filename.EndsWith(".jpg")) return true; + return false; + } + public async Task AddTip(IUserMessage message, string keywords, string content) { - var keywordList = keywords.Split(',').Select(k => k.Trim()).ToList(); - var imagePaths = new List(); + if (string.IsNullOrWhitespace(keywords)) + { + await textChannel.SendMessageAsync("No valid keywords given to store a new tip."); + return; + } + var keywordList = keywords.Split(',').Select(k => k.Trim()).Where(k -> IsValidTipKeyword(k)).ToList(); + if (keywordList.Count == 0) + { + await textChannel.SendMessageAsync("No valid keywords given to store a new tip."); + return; + } + + var imagePaths = new List(); foreach (var attachment in message.Attachments) { - if (!attachment.Filename.EndsWith(".png") && !attachment.Filename.EndsWith(".webp") && !attachment.Filename.EndsWith(".jpg")) continue; + if (!IsValidTipAttachment(attachment)) + continue; + var newFileName = Guid.NewGuid().ToString() + attachment.Filename.Substring(attachment.Filename.LastIndexOf('.')); var filePath = Path.Combine(_imageDirectory, newFileName); if (attachment.Size > _settings.TipMaxImageFileSize) @@ -96,8 +139,15 @@ public async Task AddTip(IUserMessage message, string keywords, string content) imagePaths.Add(newFileName); } + if (imagePaths.Count == 0 && string.IsNullOrWhitespace(content)) + { + await textChannel.SendMessageAsync("No valid content given to store a new tip."); + return; + } + var tip = new Tip { + // TODO: ID = original message id, // for later editing/removing tips Content = content, Keywords = keywordList, ImagePaths = imagePaths @@ -123,9 +173,9 @@ public async Task AddTip(IUserMessage message, string keywords, string content) { var builder = new EmbedBuilder() .WithTitle("Tip Added") - .WithDescription($"Your tip has been added with the keywords `{string.Join(", ", keywordList)}`.") + .WithDescription($"Your tip has been added with the keywords `{string.Join("`, `", keywordList)}`.") .WithColor(Color.Green); - + // TODO: (James) Attach the images if they exist? await textChannel.SendMessageAsync(embed: builder.Build()); @@ -134,8 +184,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) public List GetTips(string keyword) { - var regex = new Regex(keyword, RegexOptions.IgnoreCase); - return _tips.Where(kvp => kvp.Key.Split(',').Any(k => regex.IsMatch(k))) + return _tips.Where(kvp => kvp.Key.Split(',').Any(k => IsValidTipKeyword(k))) .SelectMany(kvp => kvp.Value) .Distinct() .ToList(); From 2412d9dedefe31f5e2acb88330c5ece381882ba9 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:34:28 -0500 Subject: [PATCH 08/61] Update Tip.cs * Added an Id property for editing/removing tips later. Without this, you'd have to remove multiple tips based on a keyword search. With this, however, we now have to show the Id property in any editing interfaces. It's up to the service how to choose values for Id. --- DiscordBot/Services/Tips/Components/Tip.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/Components/Tip.cs b/DiscordBot/Services/Tips/Components/Tip.cs index 4b4fdb3a..5da03420 100644 --- a/DiscordBot/Services/Tips/Components/Tip.cs +++ b/DiscordBot/Services/Tips/Components/Tip.cs @@ -1,7 +1,8 @@ namespace DiscordBot.Services.Tips.Components; -public class Tip +public class Tip: IEntity { + public ulong Id { get; set; } public string Content { get; set; } public List Keywords { get; set; } public List ImagePaths { get; set; } From a48f51ef03e35bd8dd29496e073c53b82b0f06df Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:43:17 -0500 Subject: [PATCH 09/61] Update TipService.cs * size of attachment moves into the rule check function --- DiscordBot/Services/Tips/TipService.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 4a716013..6a16fdcf 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -95,11 +95,15 @@ private bool IsValidTipKeyword(string keyword) private bool IsValidTipAttachment(IAttachment attachment) { + if (attachment.Size > _settings.TipMaxImageFileSize) + return false; + // Discord-friendly attachment image file formats only // if (attachment.Filename.EndsWith(".png")) return true; if (attachment.Filename.EndsWith(".webp")) return true; if (attachment.Filename.EndsWith(".jpg")) return true; + return false; } @@ -126,10 +130,6 @@ public async Task AddTip(IUserMessage message, string keywords, string content) var newFileName = Guid.NewGuid().ToString() + attachment.Filename.Substring(attachment.Filename.LastIndexOf('.')); var filePath = Path.Combine(_imageDirectory, newFileName); - if (attachment.Size > _settings.TipMaxImageFileSize) - { - continue; - } using var client = new HttpClient(); await using var stream = await client.GetStreamAsync(attachment.Url); From 896f1592b74f016996a9b91ce65ce62b8846f1e6 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:48:28 -0500 Subject: [PATCH 10/61] Update Tip.cs * using Discord namespace. --- DiscordBot/Services/Tips/Components/Tip.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DiscordBot/Services/Tips/Components/Tip.cs b/DiscordBot/Services/Tips/Components/Tip.cs index 5da03420..f7962ad4 100644 --- a/DiscordBot/Services/Tips/Components/Tip.cs +++ b/DiscordBot/Services/Tips/Components/Tip.cs @@ -1,3 +1,5 @@ +using Discord; + namespace DiscordBot.Services.Tips.Components; public class Tip: IEntity From 96122cd45e30215811d7bd3b02e651b03f1b3c4a Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 14:12:44 -0500 Subject: [PATCH 11/61] Pseudo-database methods for TipService.cs * pull Json serialization out of AddTip * add CommitTipDatabase to save json to file * add DumpTipDatabase to return json for debugging --- DiscordBot/Services/Tips/TipService.cs | 39 +++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 6a16fdcf..f4d551c9 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -162,12 +162,10 @@ public async Task AddTip(IUserMessage message, string keywords, string content) }); } - // In same folder, we save json files - var jsonPath = Path.Combine(_imageDirectory, "tips.json"); - await File.WriteAllTextAsync(jsonPath, JsonConvert.SerializeObject(_tips)); + CommitTipDatabase(); await _loggingService.LogAction($"[{ServiceName}] Added tip from {message.Author.Username} with keywords {string.Join(", ", keywordList)}.", ExtendedLogSeverity.Info); - + // Send a confirmation message if (message.Channel is SocketTextChannel textChannel) { @@ -182,6 +180,39 @@ public async Task AddTip(IUserMessage message, string keywords, string content) } } + public void RemoveTip(Tip tip) + { + if (tip == null) + return; + + // for all keywords in this tip, + // remove this tip from _tips[keyword] list + // if this made _tips[keyword] empty, + // remove key + + CommitTipDatabase(); + } + + private void CommitTipDatabase() + { + // In same folder, we save json files + var jsonPath = Path.Combine(_imageDirectory, "tips.json"); + await File.WriteAllTextAsync(jsonPath, JsonConvert.SerializeObject(_tips)); + } + + public string DumpTipDatabase() + { + return JsonConvert.SerializeObject(_tips); + } + + public Tip GetTip(ulong Id) + { + foreach (var kvp in _tips) + if (kvp.Value.Id == Id) + return kvp.Value; + return null; + } + public List GetTips(string keyword) { return _tips.Where(kvp => kvp.Key.Split(',').Any(k => IsValidTipKeyword(k))) From 2b7034f43ddec40dde7e91d62cd9543444e79205 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 14:26:33 -0500 Subject: [PATCH 12/61] Syntax and cleanup in TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index f4d551c9..59cc5cf6 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -78,7 +78,7 @@ private void Initialize() private bool IsValidTipKeyword(string keyword) { - // start with ascii letter + // Start with ascii letter // continue with ascii letters, digits, limited punctuation // no whitespace, no commas // @@ -115,7 +115,10 @@ public async Task AddTip(IUserMessage message, string keywords, string content) return; } - var keywordList = keywords.Split(',').Select(k => k.Trim()).Where(k -> IsValidTipKeyword(k)).ToList(); + var keywordList = keywords.Split(',') + .Select(k => k.Trim()) + .Where(k => IsValidTipKeyword(k)) + .ToList(); if (keywordList.Count == 0) { await textChannel.SendMessageAsync("No valid keywords given to store a new tip."); @@ -128,7 +131,9 @@ public async Task AddTip(IUserMessage message, string keywords, string content) if (!IsValidTipAttachment(attachment)) continue; - var newFileName = Guid.NewGuid().ToString() + attachment.Filename.Substring(attachment.Filename.LastIndexOf('.')); + var newFileName = + Guid.NewGuid().ToString() + + attachment.Filename.Substring(attachment.Filename.LastIndexOf('.')); var filePath = Path.Combine(_imageDirectory, newFileName); using var client = new HttpClient(); @@ -139,15 +144,17 @@ public async Task AddTip(IUserMessage message, string keywords, string content) imagePaths.Add(newFileName); } + // Need content and/or a valid attachment if (imagePaths.Count == 0 && string.IsNullOrWhitespace(content)) { await textChannel.SendMessageAsync("No valid content given to store a new tip."); return; } + ulong id = message.Id; var tip = new Tip { - // TODO: ID = original message id, // for later editing/removing tips + Id = id, Content = content, Keywords = keywordList, ImagePaths = imagePaths @@ -171,7 +178,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) { var builder = new EmbedBuilder() .WithTitle("Tip Added") - .WithDescription($"Your tip has been added with the keywords `{string.Join("`, `", keywordList)}`.") + .WithDescription($"Your tip has been added with the keywords `{string.Join("`, `", keywordList)}` and ID {tip.Id}.") .WithColor(Color.Green); // TODO: (James) Attach the images if they exist? @@ -215,6 +222,8 @@ public Tip GetTip(ulong Id) public List GetTips(string keyword) { + // TODO: if keyword looks numeric, get one tip based on id + return _tips.Where(kvp => kvp.Key.Split(',').Any(k => IsValidTipKeyword(k))) .SelectMany(kvp => kvp.Value) .Distinct() From f8400f4053bcdff0252943cf2ed1586bc04bc2a3 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 18:00:43 -0500 Subject: [PATCH 13/61] Update TipModule.cs Added draft implementations of commands: * removetip * dumptips * tiphelp --- DiscordBot/Modules/TipModule.cs | 37 +++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index cc4fc083..533aad12 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -20,6 +20,7 @@ public class TipModule : ModuleBase [Command("Tip")] [Summary("Find and provide pre-authored tips (images or text) by their keywords.")] + /* for now */ [RequireModerator] public async Task Tip(string keywords) { var tips = TipService.GetTips(keywords); @@ -73,12 +74,40 @@ public async Task AddTip(string keywords, string content = "") { await TipService.AddTip(Context.Message, keywords, content); } + + [Command("RemoveTip")] + [Summary("Remove a tip from the database.")] + [RequireModerator] + public async Task RemoveTip(ulong tipId) + { + Tip tip = TipService.GetTip(tipId); + if (tip == null) + { + await Context.Channel.SendMessageAsync("No such tip found to be removed."); + return; + } + + await TipService.RemoveTip(tip); + } + + [Command("DumpTips")] + [Summary("For debugging, view the tip index.")] + [RequireModerator] + public async Task DumpTipDatabase() + { + string json = TipService.DumpTipDatabase(); + await Context.Channel.SendMessageAsync( + "Tip database index as JSON:\n```\n{json}\n```"); + } #region CommandList - - [Summary("Does what you see now.")] - [Command("Ticket Help")] - public async Task TicketHelp() + + [Command("TipHelp")] + [Alias("TipsHelp")] + [Alias("HelpTip")] + [Alias("HelpTips")] + [Summary("Shows available tip database commands.")] + public async Task TipHelp() { foreach (var message in CommandHandlingService.GetCommandListMessages("TipModule", true, true, false)) { From 839d17390b2384cf698a36394342854272e40ed6 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 18:01:51 -0500 Subject: [PATCH 14/61] Change TipService RemoveTip to async Since it has an error message, RemoveTip is async. Still no implementation. --- DiscordBot/Services/Tips/TipService.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 59cc5cf6..25e1bf46 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -187,10 +187,13 @@ public async Task AddTip(IUserMessage message, string keywords, string content) } } - public void RemoveTip(Tip tip) + public async Task RemoveTip(Tip tip) { if (tip == null) + { + await textChannel.SendMessageAsync("No such tip found to be removed."); return; + } // for all keywords in this tip, // remove this tip from _tips[keyword] list From a85426427a683cf4ec27769a583394f6a885727e Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:27:42 -0500 Subject: [PATCH 15/61] Fix TipModule.cs Alias Can only have one Alias attribute --- DiscordBot/Modules/TipModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index e85db73d..ef52ba84 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -103,8 +103,8 @@ await Context.Channel.SendMessageAsync( #region CommandList [Command("TipHelp")] [Alias("TipsHelp")] - [Alias("HelpTip")] - [Alias("HelpTips")] + //[Alias("HelpTip")] + //[Alias("HelpTips")] [Summary("Shows available tip database commands.")] public async Task TipHelp() { From 29e45ee808af8c9e8c2ed353ebf695ee3290fc45 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:39:16 -0500 Subject: [PATCH 16/61] Cleanup TipModule.cs, kick build --- DiscordBot/Modules/TipModule.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index ef52ba84..afeaca07 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -103,8 +103,6 @@ await Context.Channel.SendMessageAsync( #region CommandList [Command("TipHelp")] [Alias("TipsHelp")] - //[Alias("HelpTip")] - //[Alias("HelpTips")] [Summary("Shows available tip database commands.")] public async Task TipHelp() { From 725f69502a583b762aaaab3dbbbbaf38a6bae7af Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:49:24 -0500 Subject: [PATCH 17/61] Fixes to TipService.cs * async CommitTipDatabase * walk list of tips in GetTip search --- DiscordBot/Services/Tips/TipService.cs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 25e1bf46..57338ddc 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -109,9 +109,9 @@ private bool IsValidTipAttachment(IAttachment attachment) public async Task AddTip(IUserMessage message, string keywords, string content) { - if (string.IsNullOrWhitespace(keywords)) + if (string.IsNullOrEmpty(keywords)) { - await textChannel.SendMessageAsync("No valid keywords given to store a new tip."); + await message.Channel.SendMessageAsync("No valid keywords given to store a new tip."); return; } @@ -121,7 +121,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) .ToList(); if (keywordList.Count == 0) { - await textChannel.SendMessageAsync("No valid keywords given to store a new tip."); + await message.Channel.SendMessageAsync("No valid keywords given to store a new tip."); return; } @@ -147,7 +147,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) // Need content and/or a valid attachment if (imagePaths.Count == 0 && string.IsNullOrWhitespace(content)) { - await textChannel.SendMessageAsync("No valid content given to store a new tip."); + await message.Channel.SendMessageAsync("No valid content given to store a new tip."); return; } @@ -169,7 +169,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) }); } - CommitTipDatabase(); + await CommitTipDatabase(); await _loggingService.LogAction($"[{ServiceName}] Added tip from {message.Author.Username} with keywords {string.Join(", ", keywordList)}.", ExtendedLogSeverity.Info); @@ -187,11 +187,11 @@ public async Task AddTip(IUserMessage message, string keywords, string content) } } - public async Task RemoveTip(Tip tip) + public async Task RemoveTip(IUserMessage message, Tip tip) { if (tip == null) { - await textChannel.SendMessageAsync("No such tip found to be removed."); + await message.Channel.SendMessageAsync("No such tip found to be removed."); return; } @@ -200,10 +200,10 @@ public async Task RemoveTip(Tip tip) // if this made _tips[keyword] empty, // remove key - CommitTipDatabase(); + await CommitTipDatabase(); } - private void CommitTipDatabase() + private async Task CommitTipDatabase() { // In same folder, we save json files var jsonPath = Path.Combine(_imageDirectory, "tips.json"); @@ -218,8 +218,9 @@ public string DumpTipDatabase() public Tip GetTip(ulong Id) { foreach (var kvp in _tips) - if (kvp.Value.Id == Id) - return kvp.Value; + foreach (var tip in kvp.Value) + if (tip.Id == Id) + return tip; return null; } From d4c0121d33582d415581ce50c26ac92d2fe3f6f3 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:50:24 -0500 Subject: [PATCH 18/61] Update TipModule.cs Needed `using`. --- DiscordBot/Modules/TipModule.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index afeaca07..9df6bf44 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -3,6 +3,7 @@ using DiscordBot.Attributes; using DiscordBot.Services; using DiscordBot.Services.Tips; +using DiscordBot.Services.Tips.Components; using DiscordBot.Settings; // ReSharper disable all UnusedMember.Local From 9aec4e9e465e435ff815f56b6b793f28d0a8729b Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:52:18 -0500 Subject: [PATCH 19/61] Update TipModule.cs Argument added --- DiscordBot/Modules/TipModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 9df6bf44..baae8d2b 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -88,7 +88,7 @@ public async Task RemoveTip(ulong tipId) return; } - await TipService.RemoveTip(tip); + await TipService.RemoveTip(Context.Message, tip); } [Command("DumpTips")] From a5c544b86a60c16f60d6092bcc60e93931c41835 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:53:30 -0500 Subject: [PATCH 20/61] Update TipService.cs No IsNullOrWhitespace --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 57338ddc..f6653f51 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -145,7 +145,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) } // Need content and/or a valid attachment - if (imagePaths.Count == 0 && string.IsNullOrWhitespace(content)) + if (imagePaths.Count == 0 && string.IsNullOrEmpty(content)) { await message.Channel.SendMessageAsync("No valid content given to store a new tip."); return; From 080afef5bff72ea3d415326e1a1e744f7349c74f Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 19:58:51 -0500 Subject: [PATCH 21/61] Update TipModule.cs Interpolated string --- DiscordBot/Modules/TipModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index baae8d2b..b8d7fe8a 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -98,7 +98,7 @@ public async Task DumpTipDatabase() { string json = TipService.DumpTipDatabase(); await Context.Channel.SendMessageAsync( - "Tip database index as JSON:\n```\n{json}\n```"); + $"Tip database index as JSON:\n```\n{json}\n```"); } #region CommandList From befad98189e0976a2ca491741cee5cb8b4ce00fc Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 20:14:58 -0500 Subject: [PATCH 22/61] Rewrite TipService.cs GetTips search Was finding tips without a keyword match. Try iteration instead of Linq magic. --- DiscordBot/Services/Tips/TipService.cs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index f6653f51..7b8a0cd2 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -226,11 +226,26 @@ public Tip GetTip(ulong Id) public List GetTips(string keyword) { + var found = new List(); + if (string.IsNullOrEmpty(keyword)) + return found; + // TODO: if keyword looks numeric, get one tip based on id - return _tips.Where(kvp => kvp.Key.Split(',').Any(k => IsValidTipKeyword(k))) - .SelectMany(kvp => kvp.Value) - .Distinct() + var keywordList = keywords.Split(',') + .Select(k => k.Trim()) + .Where(k => IsValidTipKeyword(k)) .ToList(); + foreach (string keyword in keywordList) + if (_tips.Contains(keyword)) + foreach (Tip tip in _tips[keyword]) + if (!found.Contains(tip)) + found.Add(tip); + return found; + + //return _tips.Where(kvp => kvp.Key.Split(',').Any(k => IsValidTipKeyword(k))) + // .SelectMany(kvp => kvp.Value) + // .Distinct() + // .ToList(); } } From 5c405330e596b3cef69a9c86ef2e6c9fe5cef6a3 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 20:21:11 -0500 Subject: [PATCH 23/61] rerun checks --- DiscordBot/Services/Tips/TipService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 7b8a0cd2..83c8f607 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -236,6 +236,7 @@ public List GetTips(string keyword) .Select(k => k.Trim()) .Where(k => IsValidTipKeyword(k)) .ToList(); + foreach (string keyword in keywordList) if (_tips.Contains(keyword)) foreach (Tip tip in _tips[keyword]) From 64f7b2b1b41a9143d28130c43659d35d9dfeda39 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 20:23:35 -0500 Subject: [PATCH 24/61] Typo in TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 83c8f607..7726a37d 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -224,13 +224,13 @@ public Tip GetTip(ulong Id) return null; } - public List GetTips(string keyword) + public List GetTips(string keywords) { var found = new List(); - if (string.IsNullOrEmpty(keyword)) + if (string.IsNullOrEmpty(keywords)) return found; - // TODO: if keyword looks numeric, get one tip based on id + // TODO: if keywords looks numeric, get one tip based on id var keywordList = keywords.Split(',') .Select(k => k.Trim()) From 4e372bf0780946f53992b692f0fdfcb43d04c545 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 20:25:41 -0500 Subject: [PATCH 25/61] ContainsKey in TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 7726a37d..5d2d4b29 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -238,7 +238,7 @@ public List GetTips(string keywords) .ToList(); foreach (string keyword in keywordList) - if (_tips.Contains(keyword)) + if (_tips.ContainsKey(keyword)) foreach (Tip tip in _tips[keyword]) if (!found.Contains(tip)) found.Add(tip); From 6a5f79be79bf8be6f2dc6cbedb334bf6e0ab9170 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 20:59:02 -0500 Subject: [PATCH 26/61] Add RemoveTip and startup logging to TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 5d2d4b29..da0a45c0 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -46,10 +46,12 @@ private void Initialize() { if (_isRunning) return; + var jsonPath = Path.Combine(_imageDirectory, "tips.json"); if (!Directory.Exists(_imageDirectory)) { + _loggingService.LogAction($"[{ServiceName}] Tip directory {_imageDirectory} did not exist.", ExtendedLogSeverity.Info); Directory.CreateDirectory(_imageDirectory); - File.WriteAllText(Path.Combine(_imageDirectory, "tips.json"), "{}"); + File.WriteAllText(jsonPath, "{}"); } else { @@ -65,11 +67,11 @@ private void Initialize() ExtendedLogSeverity.Info); } - var jsonPath = Path.Combine(_imageDirectory, "tips.json"); if (File.Exists(jsonPath)) { var json = File.ReadAllText(jsonPath); _tips = JsonConvert.DeserializeObject>>(json); + _loggingService.LogAction($"[{ServiceName}] Tip index has {_tips.Count} keywords.", ExtendedLogSeverity.Info); } } @@ -195,10 +197,14 @@ public async Task RemoveTip(IUserMessage message, Tip tip) return; } - // for all keywords in this tip, - // remove this tip from _tips[keyword] list - // if this made _tips[keyword] empty, - // remove key + foreach (string keyword in tip.Keywords) + { + if (!_tips.ContainsKey(keyword)) + continue; + _tips[keyword].Remove(tip); + if (_tips[keyword].Count == 0) + _tips.Remove(keyword); + } await CommitTipDatabase(); } From 10c5141f88713811e0996c07b2a951ccd82a1265 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 21:05:52 -0500 Subject: [PATCH 27/61] Update TipService.cs Work around CollectionExtensions fail --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index da0a45c0..6107ab8d 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -203,7 +203,7 @@ public async Task RemoveTip(IUserMessage message, Tip tip) continue; _tips[keyword].Remove(tip); if (_tips[keyword].Count == 0) - _tips.Remove(keyword); + _tips.Remove(keyword, out var _); } await CommitTipDatabase(); From 7399b86cdf5cde42007a45b593efc708c88b3116 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 21:45:50 -0500 Subject: [PATCH 28/61] Initialize TipService.cs relative to ServerRootPath --- DiscordBot/Services/Tips/TipService.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 6107ab8d..cc240d2f 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -29,6 +29,13 @@ public TipService(BotSettings settings, ILoggingService loggingService) { _settings = settings; _loggingService = loggingService; + + if (string.IsNullOrEmpty(_settings.ServerRootPath)) + { + _loggingService.LogAction($"[{ServiceName}] ServerRootPath not set, service will not run.", ExtendedLogSeverity.Warning); + _isRunning = false; + return; + } if (string.IsNullOrEmpty(_settings.TipImageDirectory)) { @@ -36,8 +43,8 @@ public TipService(BotSettings settings, ILoggingService loggingService) _isRunning = false; return; } - - _imageDirectory = Path.Combine(Directory.GetCurrentDirectory(), _settings.TipImageDirectory); + + _imageDirectory = Path.Combine(_settings.ServerRootPath, _settings.TipImageDirectory); Initialize(); } From 48359d3e720b3e15c08db05f9d73439523b7400d Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 22:03:17 -0500 Subject: [PATCH 29/61] Update TipModule.cs path Use the same folder as TipService. --- DiscordBot/Modules/TipModule.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index b8d7fe8a..84956d7b 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -44,11 +44,14 @@ public async Task Tip(string keywords) builder.AddField(tip.Keywords.Count == 1 ? tip.Keywords[0] : "Multiple Keywords", tip.Content); } } + + //TODO: ask TipService for full path given an image path + string imageDirectory = Path.Combine(Settings.ServerRootPath, Settings.TipImageDirectory); var attachments = tips .Where(tip => tip.ImagePaths != null && tip.ImagePaths.Any()) .SelectMany(tip => tip.ImagePaths) - .Select(imagePath => new FileAttachment(Path.Combine(Settings.TipImageDirectory, imagePath))) + .Select(imagePath => new FileAttachment(Path.Combine(imageDirectory, imagePath))) .ToList(); if (attachments.Count > 0) From c9a08738e0c2431a94d7170b7afa2e867a950d5c Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 22:24:17 -0500 Subject: [PATCH 30/61] Add GetTipPath to TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 36 +++++++++++++++++++------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index cc240d2f..0f82b268 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -15,7 +15,8 @@ namespace DiscordBot.Services.Tips; public class TipService { private const string ServiceName = "TipService"; - + private const string DatabaseName = "tips.json"; + private readonly BotSettings _settings; private readonly ILoggingService _loggingService; private readonly string _imageDirectory; @@ -53,7 +54,7 @@ private void Initialize() { if (_isRunning) return; - var jsonPath = Path.Combine(_imageDirectory, "tips.json"); + var jsonPath = GetTipPath(DatabaseName);; if (!Directory.Exists(_imageDirectory)) { _loggingService.LogAction($"[{ServiceName}] Tip directory {_imageDirectory} did not exist.", ExtendedLogSeverity.Info); @@ -115,7 +116,12 @@ private bool IsValidTipAttachment(IAttachment attachment) return false; } - + + public string GetTipPath(string filename) + { + return Path.Combine(_imageDirectory, filename); + } + public async Task AddTip(IUserMessage message, string keywords, string content) { if (string.IsNullOrEmpty(keywords)) @@ -143,7 +149,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) var newFileName = Guid.NewGuid().ToString() + attachment.Filename.Substring(attachment.Filename.LastIndexOf('.')); - var filePath = Path.Combine(_imageDirectory, newFileName); + var filePath = GetTipPath(newFileName); using var client = new HttpClient(); await using var stream = await client.GetStreamAsync(attachment.Url); @@ -213,13 +219,28 @@ public async Task RemoveTip(IUserMessage message, Tip tip) _tips.Remove(keyword, out var _); } + foreach (string imagePath in tip.ImagePaths) + { + try { File.Delete(imagePath); } + catch (Exception _) { } + } + await CommitTipDatabase(); } + public async Task ReplaceTip(IUserMessage message, string keywords, string content) + { + // TODO: get tip + // TODO: if not found, bail + // TODO: remove tip + // TODO: add tip + // REVIEW: causes two CommitTipDatabase calls + } + private async Task CommitTipDatabase() { // In same folder, we save json files - var jsonPath = Path.Combine(_imageDirectory, "tips.json"); + var jsonPath = GetTipPath(DatabaseName); await File.WriteAllTextAsync(jsonPath, JsonConvert.SerializeObject(_tips)); } @@ -256,10 +277,5 @@ public List GetTips(string keywords) if (!found.Contains(tip)) found.Add(tip); return found; - - //return _tips.Where(kvp => kvp.Key.Split(',').Any(k => IsValidTipKeyword(k))) - // .SelectMany(kvp => kvp.Value) - // .Distinct() - // .ToList(); } } From 957aac6423a0a141bd2d9520aae3639587ff5411 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 22:26:17 -0500 Subject: [PATCH 31/61] Update TipModule.cs to use GetTipPath --- DiscordBot/Modules/TipModule.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 84956d7b..9f3e8b59 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -44,14 +44,11 @@ public async Task Tip(string keywords) builder.AddField(tip.Keywords.Count == 1 ? tip.Keywords[0] : "Multiple Keywords", tip.Content); } } - - //TODO: ask TipService for full path given an image path - string imageDirectory = Path.Combine(Settings.ServerRootPath, Settings.TipImageDirectory); var attachments = tips .Where(tip => tip.ImagePaths != null && tip.ImagePaths.Any()) .SelectMany(tip => tip.ImagePaths) - .Select(imagePath => new FileAttachment(Path.Combine(imageDirectory, imagePath))) + .Select(imagePath => new FileAttachment(TipService.GetTipPath(imagePath))) .ToList(); if (attachments.Count > 0) From 3254c9d7a95e8a2043a372a248fb99a3566aa8dd Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 22:54:56 -0500 Subject: [PATCH 32/61] More TipService.cs RemoveTip updates --- DiscordBot/Services/Tips/TipService.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 0f82b268..38945db3 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -221,11 +221,21 @@ public async Task RemoveTip(IUserMessage message, Tip tip) foreach (string imagePath in tip.ImagePaths) { - try { File.Delete(imagePath); } - catch (Exception _) { } + try + { + File.Delete(GetTipPath(imagePath)); + } + catch (Exception e) + { + await _loggingService.LogAction( + $"[{ServiceName}] Failed to remove tip image: {e}", ExtendedLogSeverity.Warning); + } } await CommitTipDatabase(); + + string keywords = string.Join("`, `", tip.Keywords); + await message.Channel.SendMessageAsync("Removed a tip with keywords `{keywords}`."); } public async Task ReplaceTip(IUserMessage message, string keywords, string content) From 36244dda458119fccdd288c580e2a1e08e2ee179 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 23:11:01 -0500 Subject: [PATCH 33/61] Support ReadOnly ops in TipService.cs If usage space is exceeded on startup, no new tips. --- DiscordBot/Services/Tips/TipService.cs | 34 ++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 38945db3..974c0c9c 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -23,6 +23,7 @@ public class TipService private ConcurrentDictionary> _tips = new(); private bool _isRunning = false; + private bool _readOnly = false; private Regex keywordPattern = null; @@ -53,7 +54,8 @@ public TipService(BotSettings settings, ILoggingService loggingService) private void Initialize() { if (_isRunning) return; - + + _readOnly = false; var jsonPath = GetTipPath(DatabaseName);; if (!Directory.Exists(_imageDirectory)) { @@ -66,11 +68,12 @@ private void Initialize() var directorySize = new DirectoryInfo(_imageDirectory).EnumerateFiles("*.*", SearchOption.AllDirectories).Sum(file => file.Length); if (directorySize > _settings.TipMaxDirectoryFileSize) { - _loggingService.LogAction($"[{ServiceName}] Tip directory size is {directorySize / 1024 / 1024} MB, exceeding the limit of {_settings.TipMaxDirectoryFileSize / 1024 / 1024} MB, no additional content will be added during this session.", ExtendedLogSeverity.Warning); + _loggingService.LogAction($"[{ServiceName}] Tip directory size is {directorySize / 1024 / 1024f:.#} MB, exceeding the limit of {_settings.TipMaxDirectoryFileSize / 1024 / 1024f:.#} MB, no additional content will be added during this session.", ExtendedLogSeverity.Warning); + _readOnly = true; } else { - _loggingService.LogAction($"[{ServiceName}] Tip directory size is {directorySize / 1024 / 1024} MB, within the limit of {_settings.TipMaxDirectoryFileSize / 1024 / 1024} MB.", ExtendedLogSeverity.Info); + _loggingService.LogAction($"[{ServiceName}] Tip directory size is {directorySize / 1024 / 1024f:.#} MB, within the limit of {_settings.TipMaxDirectoryFileSize / 1024 / 1024f:.#} MB.", ExtendedLogSeverity.Info); _loggingService.LogAction($"[{ServiceName}] Tip directory contains {new DirectoryInfo(_imageDirectory).EnumerateFiles("*.*", SearchOption.AllDirectories).Count()} files.", ExtendedLogSeverity.Info); } @@ -79,7 +82,9 @@ private void Initialize() { var json = File.ReadAllText(jsonPath); _tips = JsonConvert.DeserializeObject>>(json); - _loggingService.LogAction($"[{ServiceName}] Tip index has {_tips.Count} keywords.", ExtendedLogSeverity.Info); + _loggingService.LogAction( + $"[{ServiceName}] Tip index has {_tips.Count} keywords.", + ExtendedLogSeverity.Info); } } @@ -124,6 +129,12 @@ public string GetTipPath(string filename) public async Task AddTip(IUserMessage message, string keywords, string content) { + if (_readOnly) + { + await message.Channel.SendMessageAsync("Cannot add or modify tips in the database at this time."); + return; + } + if (string.IsNullOrEmpty(keywords)) { await message.Channel.SendMessageAsync("No valid keywords given to store a new tip."); @@ -186,14 +197,17 @@ public async Task AddTip(IUserMessage message, string keywords, string content) await CommitTipDatabase(); - await _loggingService.LogAction($"[{ServiceName}] Added tip from {message.Author.Username} with keywords {string.Join(", ", keywordList)}.", ExtendedLogSeverity.Info); + string words = string.Join("`, `", keywordList); + await _loggingService.LogAction( + $"[{ServiceName}] Added tip from {message.Author.Username} with keywords `{words)`}.", + ExtendedLogSeverity.Info); // Send a confirmation message if (message.Channel is SocketTextChannel textChannel) { var builder = new EmbedBuilder() .WithTitle("Tip Added") - .WithDescription($"Your tip has been added with the keywords `{string.Join("`, `", keywordList)}` and ID {tip.Id}.") + .WithDescription($"Your tip has been added with the keywords `{words}` and ID {tip.Id}.") .WithColor(Color.Green); // TODO: (James) Attach the images if they exist? @@ -235,11 +249,17 @@ await _loggingService.LogAction( await CommitTipDatabase(); string keywords = string.Join("`, `", tip.Keywords); - await message.Channel.SendMessageAsync("Removed a tip with keywords `{keywords}`."); + await message.Channel.SendMessageAsync($"Removed a tip with keywords `{keywords}`."); } public async Task ReplaceTip(IUserMessage message, string keywords, string content) { + if (_readOnly) + { + await message.Channel.SendMessageAsync("Cannot add or modify tips in the database at this time."); + return; + } + // TODO: get tip // TODO: if not found, bail // TODO: remove tip From 07a2961faeeef4a791f6aba6984d5d357fa80e0d Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 24 Apr 2025 23:12:27 -0500 Subject: [PATCH 34/61] Fix TipService.cs string syntax --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 974c0c9c..65126695 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -199,7 +199,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) string words = string.Join("`, `", keywordList); await _loggingService.LogAction( - $"[{ServiceName}] Added tip from {message.Author.Username} with keywords `{words)`}.", + $"[{ServiceName}] Added tip from {message.Author.Username} with keywords `{words}`.", ExtendedLogSeverity.Info); // Send a confirmation message From 8612fbc37d0e3e8ed9ca8a16c0347d01e13e31be Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 08:28:39 -0500 Subject: [PATCH 35/61] Update TipService.cs RemoveTip --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 65126695..42d9ac12 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -228,7 +228,7 @@ public async Task RemoveTip(IUserMessage message, Tip tip) { if (!_tips.ContainsKey(keyword)) continue; - _tips[keyword].Remove(tip); + _tips[keyword].RemoveAll(t => t.Id == tip.Id); if (_tips[keyword].Count == 0) _tips.Remove(keyword, out var _); } From fefdab6abecf7ff63ffc9d9cc4232798e078a3c7 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 09:30:10 -0500 Subject: [PATCH 36/61] GetTips in TipService.cs more exclusive --- DiscordBot/Services/Tips/TipService.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 42d9ac12..4df2b538 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -85,6 +85,7 @@ private void Initialize() _loggingService.LogAction( $"[{ServiceName}] Tip index has {_tips.Count} keywords.", ExtendedLogSeverity.Info); + //NOTE: elements of type Tip are not de-duplicated after loading } } @@ -301,11 +302,23 @@ public List GetTips(string keywords) .Where(k => IsValidTipKeyword(k)) .ToList(); +#if true + // boolean AND search foreach (string keyword in keywordList) if (_tips.ContainsKey(keyword)) foreach (Tip tip in _tips[keyword]) - if (!found.Contains(tip)) + if (tip.Keywords.Intersect(keywordList).Count == keywordList.Count) + if (!found.Any(t => t.Id == tip.Id) + found.Add(tip); +#else + // boolean OR search + foreach (string keyword in keywordList) + if (_tips.ContainsKey(keyword)) + foreach (Tip tip in _tips[keyword]) + if (!found.Any(t => t.Id == tip.Id)) found.Add(tip); +#endif + return found; } } From ed613b2ab109533bb0c8fd2afaba2ece0e0c8f62 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 09:32:14 -0500 Subject: [PATCH 37/61] Fix TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 4df2b538..e4333c85 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -308,7 +308,7 @@ public List GetTips(string keywords) if (_tips.ContainsKey(keyword)) foreach (Tip tip in _tips[keyword]) if (tip.Keywords.Intersect(keywordList).Count == keywordList.Count) - if (!found.Any(t => t.Id == tip.Id) + if (!found.Any(t => t.Id == tip.Id)) found.Add(tip); #else // boolean OR search From 071b4e6dc91c00613c3c1dcf7922b9442c74b8c7 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 09:35:25 -0500 Subject: [PATCH 38/61] Count in TipService.cs GetTips --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index e4333c85..cb55d1d5 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -307,7 +307,7 @@ public List GetTips(string keywords) foreach (string keyword in keywordList) if (_tips.ContainsKey(keyword)) foreach (Tip tip in _tips[keyword]) - if (tip.Keywords.Intersect(keywordList).Count == keywordList.Count) + if (tip.Keywords.Intersect(keywordList).Count() == keywordList.Count) if (!found.Any(t => t.Id == tip.Id)) found.Add(tip); #else From 0840e4667de1e32d5f6ab96e6edc0c0d9fe8318d Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:20:35 -0500 Subject: [PATCH 39/61] TipService.cs GetAllTips --- DiscordBot/Services/Tips/TipService.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index cb55d1d5..5c974dcc 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -289,6 +289,18 @@ public Tip GetTip(ulong Id) return null; } + public List GetAllTips() + { + var found = new List(); + + foreach (string keyword in keywordList) + foreach (Tip tip in _tips[keyword]) + if (!found.Any(t => t.Id == tip.Id)) + found.Add(tip); + + return found; + } + public List GetTips(string keywords) { var found = new List(); From 9b829dfff8bf8e21e605df46982faae89bf484e5 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:20:48 -0500 Subject: [PATCH 40/61] TipModule.cs ListTips --- DiscordBot/Modules/TipModule.cs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 9f3e8b59..da2d62d6 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -32,7 +32,7 @@ public async Task Tip(string keywords) } var isAnyTextTips = tips.Any(tip => !string.IsNullOrEmpty(tip.Content)); - EmbedBuilder builder = new EmbedBuilder(); + var builder = new EmbedBuilder(); if (isAnyTextTips) { // Loop through tips in order, have dot point list of the .Content property in an embed @@ -100,6 +100,28 @@ public async Task DumpTipDatabase() await Context.Channel.SendMessageAsync( $"Tip database index as JSON:\n```\n{json}\n```"); } + + [Command("ListTips")] + [Summary("List available tips by their keywords.")] + [RequireModerator] + public async Task ListTips() + { + List tips = TipService.GetAllTips().OrderBy(t => t.Id); + + // TODO: paginate if long list of tips + + var builder = new EmbedBuilder(); + builder + .WithTitle("List of Tips") + .WithDescription("Tips available for the following keywords:"); + foreach (var tip in tips) + { + string keywords = string.Join("`, `", tip.Keywords.OrderBy(k => k); + builder.AddField(tip.Id, $"`{keywords}`"); + } + await ReplyAsync(embed: builder.Build()); + + } #region CommandList [Command("TipHelp")] From f859158d48f34567942d2db6da417f028051ddbf Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:21:54 -0500 Subject: [PATCH 41/61] Fix TipModule.cs --- DiscordBot/Modules/TipModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index da2d62d6..f2aa3d0f 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -116,7 +116,7 @@ public async Task ListTips() .WithDescription("Tips available for the following keywords:"); foreach (var tip in tips) { - string keywords = string.Join("`, `", tip.Keywords.OrderBy(k => k); + string keywords = string.Join("`, `", tip.Keywords.OrderBy(k => k)); builder.AddField(tip.Id, $"`{keywords}`"); } await ReplyAsync(embed: builder.Build()); From 8d758af3567d138cc742f75826a81c3133438174 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:24:49 -0500 Subject: [PATCH 42/61] TipService.cs GetAllTips --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 5c974dcc..7d041718 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -293,7 +293,7 @@ public List GetAllTips() { var found = new List(); - foreach (string keyword in keywordList) + foreach (string keyword in _tips) foreach (Tip tip in _tips[keyword]) if (!found.Any(t => t.Id == tip.Id)) found.Add(tip); From 4c0ea2c6975b0f64cb98ec3d3e593e672fa1035d Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:26:24 -0500 Subject: [PATCH 43/61] Update TipModule.cs ListTips --- DiscordBot/Modules/TipModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index f2aa3d0f..0c583c23 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -106,7 +106,7 @@ await Context.Channel.SendMessageAsync( [RequireModerator] public async Task ListTips() { - List tips = TipService.GetAllTips().OrderBy(t => t.Id); + List tips = TipService.GetAllTips().OrderBy(t => t.Id).ToList(); // TODO: paginate if long list of tips @@ -117,7 +117,7 @@ public async Task ListTips() foreach (var tip in tips) { string keywords = string.Join("`, `", tip.Keywords.OrderBy(k => k)); - builder.AddField(tip.Id, $"`{keywords}`"); + builder.AddField($"ID: {tip.Id}", $"`{keywords}`"); } await ReplyAsync(embed: builder.Build()); From d07b22dad26c8b7586cae1a4b16553e1e77ab5e2 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:27:36 -0500 Subject: [PATCH 44/61] Update TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 7d041718..a32c5395 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -293,7 +293,7 @@ public List GetAllTips() { var found = new List(); - foreach (string keyword in _tips) + foreach (string keyword in _tips.Keys) foreach (Tip tip in _tips[keyword]) if (!found.Any(t => t.Id == tip.Id)) found.Add(tip); From 8abe72daa4fa6379785c7a224962b1136cec9cca Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:42:51 -0500 Subject: [PATCH 45/61] Update TipModule.cs DumpTips chunking --- DiscordBot/Modules/TipModule.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 0c583c23..8e17ba6b 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -97,8 +97,18 @@ public async Task RemoveTip(ulong tipId) public async Task DumpTipDatabase() { string json = TipService.DumpTipDatabase(); - await Context.Channel.SendMessageAsync( - $"Tip database index as JSON:\n```\n{json}\n```"); + string prefix = "Tip database index as JSON:\n"; + int chunkSize = 1000; + while (!string.IsNullOrEmpty(json)) + { + string chunk = json.Substring(0, chunkSize); + json = json.Substring(chunkSize); + await Context.Channel.SendMessageAsync( + $"{prefix}```\n{chunk}\n```"); + prefix = "..."; + if (!string.IsNullOrEmpty(json)) + await Task.Delay(1000); + } } [Command("ListTips")] From 56301bfeb78a8159589aad824f0f9727e6a1eeac Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:54:53 -0500 Subject: [PATCH 46/61] Update TipModule.cs --- DiscordBot/Modules/TipModule.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 8e17ba6b..d246e3bb 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -98,16 +98,17 @@ public async Task DumpTipDatabase() { string json = TipService.DumpTipDatabase(); string prefix = "Tip database index as JSON:\n"; - int chunkSize = 1000; + int chunkSize = 1500; + int chunkTime = 2000; while (!string.IsNullOrEmpty(json)) { string chunk = json.Substring(0, chunkSize); json = json.Substring(chunkSize); await Context.Channel.SendMessageAsync( $"{prefix}```\n{chunk}\n```"); - prefix = "..."; + prefix = string.Empty; if (!string.IsNullOrEmpty(json)) - await Task.Delay(1000); + await Task.Delay(chunkTime); } } From 6ea4bf0b51008b9b8df219eb4db642fb7ef84e85 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:13:20 -0500 Subject: [PATCH 47/61] Update TipModule.cs chunking --- DiscordBot/Modules/TipModule.cs | 44 +++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index d246e3bb..87c01cd3 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -102,8 +102,12 @@ public async Task DumpTipDatabase() int chunkTime = 2000; while (!string.IsNullOrEmpty(json)) { - string chunk = json.Substring(0, chunkSize); - json = json.Substring(chunkSize); + string chunk = json; + if (json.Length > chunkSize) + { + chunk = json.Substring(0, chunkSize); + json = json.Substring(chunkSize); + } await Context.Channel.SendMessageAsync( $"{prefix}```\n{chunk}\n```"); prefix = string.Empty; @@ -118,20 +122,34 @@ await Context.Channel.SendMessageAsync( public async Task ListTips() { List tips = TipService.GetAllTips().OrderBy(t => t.Id).ToList(); + int chunkCount = 10; + int chunkTime = 2000; + bool first = true; - // TODO: paginate if long list of tips + while (tips.Count > 0) + { + var builder = new EmbedBuilder(); + if (first) + { + builder + .WithTitle("List of Tips") + .WithDescription("Tips available for the following keywords:"); + first = false; + } - var builder = new EmbedBuilder(); - builder - .WithTitle("List of Tips") - .WithDescription("Tips available for the following keywords:"); - foreach (var tip in tips) - { - string keywords = string.Join("`, `", tip.Keywords.OrderBy(k => k)); - builder.AddField($"ID: {tip.Id}", $"`{keywords}`"); - } - await ReplyAsync(embed: builder.Build()); + int chunk = 0; + while (tips.Count > 0 && chunk < chunkCount) + { + string keywords = string.Join("`, `", tips[0].Keywords.OrderBy(k => k)); + builder.AddField($"ID: {tips[0].Id}", $"`{keywords}`"); + tips.RemoveAt(0); + chunk++; + } + await ReplyAsync(embed: builder.Build()); + if (tips.Count > 0) + await Task.Delay(chunkTime); + } } #region CommandList From 413dc072db1fc971e766af4ad014f9205dcb96f4 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:34:08 -0500 Subject: [PATCH 48/61] Update TipModule.cs chunk fix --- DiscordBot/Modules/TipModule.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 87c01cd3..2647baf1 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -104,10 +104,8 @@ public async Task DumpTipDatabase() { string chunk = json; if (json.Length > chunkSize) - { chunk = json.Substring(0, chunkSize); - json = json.Substring(chunkSize); - } + json = json.Substring(chunkSize); await Context.Channel.SendMessageAsync( $"{prefix}```\n{chunk}\n```"); prefix = string.Empty; @@ -141,7 +139,8 @@ public async Task ListTips() while (tips.Count > 0 && chunk < chunkCount) { string keywords = string.Join("`, `", tips[0].Keywords.OrderBy(k => k)); - builder.AddField($"ID: {tips[0].Id}", $"`{keywords}`"); + string images = String.Concat(Enumerable.Repeat(" :frame_photo:", tip[0].ImagePaths.Count).ToArray()); + builder.AddField($"ID: {tips[0].Id} {images}", $"`{keywords}`"); tips.RemoveAt(0); chunk++; } From 859117e3ea4737da7caba4cbce27817df38a7d85 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:35:20 -0500 Subject: [PATCH 49/61] Update TipModule.cs --- DiscordBot/Modules/TipModule.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 2647baf1..08fc92de 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -139,7 +139,9 @@ public async Task ListTips() while (tips.Count > 0 && chunk < chunkCount) { string keywords = string.Join("`, `", tips[0].Keywords.OrderBy(k => k)); - string images = String.Concat(Enumerable.Repeat(" :frame_photo:", tip[0].ImagePaths.Count).ToArray()); + string images = String.Concat( + Enumerable.Repeat(" :frame_photo:", + tips[0].ImagePaths.Count).ToArray()); builder.AddField($"ID: {tips[0].Id} {images}", $"`{keywords}`"); tips.RemoveAt(0); chunk++; From 3f5142d5abfc2b40d1cef2d0a240897deaf8a080 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 11:43:08 -0500 Subject: [PATCH 50/61] Update TipModule.cs chunking --- DiscordBot/Modules/TipModule.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 08fc92de..ca3e28ba 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -104,8 +104,14 @@ public async Task DumpTipDatabase() { string chunk = json; if (json.Length > chunkSize) + { chunk = json.Substring(0, chunkSize); - json = json.Substring(chunkSize); + json = json.Substring(chunkSize); + } + else + { + json = string.Empty; + } await Context.Channel.SendMessageAsync( $"{prefix}```\n{chunk}\n```"); prefix = string.Empty; From 879c1921040a27b3d5ce9f2899969a48d24ef3fd Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:38:21 -0500 Subject: [PATCH 51/61] Update TipService.cs ReplaceTip --- DiscordBot/Services/Tips/TipService.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index a32c5395..d5cd8a96 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -253,7 +253,7 @@ await _loggingService.LogAction( await message.Channel.SendMessageAsync($"Removed a tip with keywords `{keywords}`."); } - public async Task ReplaceTip(IUserMessage message, string keywords, string content) + public async Task ReplaceTip(IUserMessage message, Tip tip, string content) { if (_readOnly) { @@ -261,10 +261,14 @@ public async Task ReplaceTip(IUserMessage message, string keywords, string conte return; } - // TODO: get tip - // TODO: if not found, bail - // TODO: remove tip - // TODO: add tip + if (tip == null) + { + await message.Channel.SendMessageAsync("No such tip found to be replaced."); + return; + } + + RemoveTip(message, tip); + AddTip(message, string.Join(",", tip.Keywords), content); // REVIEW: causes two CommitTipDatabase calls } From 348463c2526425dd995a0e875cd2f3e5462d15d5 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:50:34 -0500 Subject: [PATCH 52/61] Update TipModule.cs show tip id --- DiscordBot/Modules/TipModule.cs | 36 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index ca3e28ba..f924d0f8 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -9,6 +9,7 @@ // ReSharper disable all UnusedMember.Local namespace DiscordBot.Modules; +[Group("TipModule"), Alias("")] public class TipModule : ModuleBase { #region Dependency Injection @@ -21,7 +22,7 @@ public class TipModule : ModuleBase [Command("Tip")] [Summary("Find and provide pre-authored tips (images or text) by their keywords.")] - /* for now */ [RequireModerator] + /* for now */ [RequireModerator] /* maybe Helper too */ public async Task Tip(string keywords) { var tips = TipService.GetTips(keywords); @@ -51,16 +52,18 @@ public async Task Tip(string keywords) .Select(imagePath => new FileAttachment(TipService.GetTipPath(imagePath))) .ToList(); + builder.WithFooter(footer => footer.WithText($"-# Tip ID {tip.Id}") ); + if (attachments.Count > 0) { - if (isAnyTextTips) - { + //if (isAnyTextTips) + //{ await Context.Channel.SendFilesAsync(attachments, embed: builder.Build()); - } - else - { - await Context.Channel.SendFilesAsync(attachments); - } + //} + //else + //{ + // await Context.Channel.SendFilesAsync(attachments); + //} } else { @@ -90,6 +93,21 @@ public async Task RemoveTip(ulong tipId) await TipService.RemoveTip(Context.Message, tip); } + + [Command("ReplaceTip")] + [Summary("Replace image content of an existing tip in the database.")] + [RequireModerator] + public async Task ReplaceTip(ulong tipId, string content = "") + { + Tip tip = TipService.GetTip(tipId); + if (tip == null) + { + await Context.Channel.SendMessageAsync("No such tip found to be replaced."); + return; + } + + await TipService.ReplaceTip(Context.Message, keywords, content); + } [Command("DumpTips")] [Summary("For debugging, view the tip index.")] @@ -98,7 +116,7 @@ public async Task DumpTipDatabase() { string json = TipService.DumpTipDatabase(); string prefix = "Tip database index as JSON:\n"; - int chunkSize = 1500; + int chunkSize = 1800; int chunkTime = 2000; while (!string.IsNullOrEmpty(json)) { From 86ab63258e94db638f7118e44105339badc718f2 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:56:34 -0500 Subject: [PATCH 53/61] Update TipModule.cs --- DiscordBot/Modules/TipModule.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index f924d0f8..5096854c 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -52,7 +52,8 @@ public async Task Tip(string keywords) .Select(imagePath => new FileAttachment(TipService.GetTipPath(imagePath))) .ToList(); - builder.WithFooter(footer => footer.WithText($"-# Tip ID {tip.Id}") ); + var ids = string.Join(" ", tips.Select(t => t.Id.ToString()).ToArray()); + builder.WithFooter(footer => footer.WithText($"-# Tip ID {ids}") ); if (attachments.Count > 0) { @@ -106,7 +107,7 @@ public async Task ReplaceTip(ulong tipId, string content = "") return; } - await TipService.ReplaceTip(Context.Message, keywords, content); + await TipService.ReplaceTip(Context.Message, string.Join(",", tip.Keywords), content); } [Command("DumpTips")] From 571d9f4cec9c203bfb2d1aa7a558c84d866278db Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:57:26 -0500 Subject: [PATCH 54/61] Update TipModule.cs --- DiscordBot/Modules/TipModule.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 5096854c..3e0da909 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -107,7 +107,7 @@ public async Task ReplaceTip(ulong tipId, string content = "") return; } - await TipService.ReplaceTip(Context.Message, string.Join(",", tip.Keywords), content); + await TipService.ReplaceTip(Context.Message, tip, content); } [Command("DumpTips")] From bec5b2b51e9a6bbbbfc8497d49513da302ddf4ab Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:07:14 -0500 Subject: [PATCH 55/61] Update TipModule.cs --- DiscordBot/Modules/TipModule.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 3e0da909..4abf9276 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -9,7 +9,7 @@ // ReSharper disable all UnusedMember.Local namespace DiscordBot.Modules; -[Group("TipModule"), Alias("")] +[Group("TipModule")] public class TipModule : ModuleBase { #region Dependency Injection @@ -52,24 +52,24 @@ public async Task Tip(string keywords) .Select(imagePath => new FileAttachment(TipService.GetTipPath(imagePath))) .ToList(); - var ids = string.Join(" ", tips.Select(t => t.Id.ToString()).ToArray()); - builder.WithFooter(footer => footer.WithText($"-# Tip ID {ids}") ); - if (attachments.Count > 0) { - //if (isAnyTextTips) - //{ + if (isAnyTextTips) + { await Context.Channel.SendFilesAsync(attachments, embed: builder.Build()); - //} - //else - //{ - // await Context.Channel.SendFilesAsync(attachments); - //} + } + else + { + await Context.Channel.SendFilesAsync(attachments); + } } else { await ReplyAsync(embed: builder.Build()); } + + var ids = string.Join(" ", tips.Select(t => t.Id.ToString()).ToArray()); + await ReplyAsync($"-# Tip ID {ids}"); } [Command("AddTip")] From 87516d3eafccf067697f0925cc5e759e74676f3e Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Fri, 25 Apr 2025 13:17:32 -0500 Subject: [PATCH 56/61] Update TipModule.cs --- DiscordBot/Modules/TipModule.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 4abf9276..974c2ea1 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -9,7 +9,6 @@ // ReSharper disable all UnusedMember.Local namespace DiscordBot.Modules; -[Group("TipModule")] public class TipModule : ModuleBase { #region Dependency Injection From 042418f3d7e1bc59b5312b7c9d2352f67c661213 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:04:52 -0500 Subject: [PATCH 57/61] Lint TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index d5cd8a96..5f788241 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -3,7 +3,6 @@ using System.IO; using System.Net; using System.Net.Http; -using System.Text.RegularExpressions; using Discord; using Discord.WebSocket; using DiscordBot.Services.Tips.Components; @@ -299,7 +298,7 @@ public List GetAllTips() foreach (string keyword in _tips.Keys) foreach (Tip tip in _tips[keyword]) - if (!found.Any(t => t.Id == tip.Id)) + if (found.All(t => t.Id != tip.Id)) found.Add(tip); return found; @@ -321,17 +320,17 @@ public List GetTips(string keywords) #if true // boolean AND search foreach (string keyword in keywordList) - if (_tips.ContainsKey(keyword)) - foreach (Tip tip in _tips[keyword]) + if (var tips = _tips.TryGetValue(keyword)) + foreach (Tip tip in tips) if (tip.Keywords.Intersect(keywordList).Count() == keywordList.Count) - if (!found.Any(t => t.Id == tip.Id)) + if (found.All(t => t.Id != tip.Id)) found.Add(tip); #else // boolean OR search foreach (string keyword in keywordList) - if (_tips.ContainsKey(keyword)) - foreach (Tip tip in _tips[keyword]) - if (!found.Any(t => t.Id == tip.Id)) + if (var tips = _tips.TryGetValue(keyword)) + foreach (Tip tip in tips) + if (found.All(t => t.Id != tip.Id)) found.Add(tip); #endif From 40206bbfee12fdd070f300b88a15e6497bd3d905 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:09:09 -0500 Subject: [PATCH 58/61] Lint TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 5f788241..69115015 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -320,7 +320,7 @@ public List GetTips(string keywords) #if true // boolean AND search foreach (string keyword in keywordList) - if (var tips = _tips.TryGetValue(keyword)) + if (_tips.TryGetValue(keyword, out var list)) foreach (Tip tip in tips) if (tip.Keywords.Intersect(keywordList).Count() == keywordList.Count) if (found.All(t => t.Id != tip.Id)) @@ -328,7 +328,7 @@ public List GetTips(string keywords) #else // boolean OR search foreach (string keyword in keywordList) - if (var tips = _tips.TryGetValue(keyword)) + if (_tips.TryGetValue(keyword, out var list)) foreach (Tip tip in tips) if (found.All(t => t.Id != tip.Id)) found.Add(tip); From f1052318626b258029689fa22f56400161077c13 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:10:25 -0500 Subject: [PATCH 59/61] Lint TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index 69115015..f2bb82ea 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -320,7 +320,7 @@ public List GetTips(string keywords) #if true // boolean AND search foreach (string keyword in keywordList) - if (_tips.TryGetValue(keyword, out var list)) + if (_tips.TryGetValue(keyword, out var tips)) foreach (Tip tip in tips) if (tip.Keywords.Intersect(keywordList).Count() == keywordList.Count) if (found.All(t => t.Id != tip.Id)) @@ -328,7 +328,7 @@ public List GetTips(string keywords) #else // boolean OR search foreach (string keyword in keywordList) - if (_tips.TryGetValue(keyword, out var list)) + if (_tips.TryGetValue(keyword, out var tips)) foreach (Tip tip in tips) if (found.All(t => t.Id != tip.Id)) found.Add(tip); From 7d5616c689f248ceec03d0246198521a21f7175c Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:16:09 -0500 Subject: [PATCH 60/61] Lint TipService.cs --- DiscordBot/Services/Tips/TipService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DiscordBot/Services/Tips/TipService.cs b/DiscordBot/Services/Tips/TipService.cs index f2bb82ea..b94490c0 100644 --- a/DiscordBot/Services/Tips/TipService.cs +++ b/DiscordBot/Services/Tips/TipService.cs @@ -143,7 +143,7 @@ public async Task AddTip(IUserMessage message, string keywords, string content) var keywordList = keywords.Split(',') .Select(k => k.Trim()) - .Where(k => IsValidTipKeyword(k)) + .Where(IsValidTipKeyword) .ToList(); if (keywordList.Count == 0) { @@ -230,7 +230,7 @@ public async Task RemoveTip(IUserMessage message, Tip tip) continue; _tips[keyword].RemoveAll(t => t.Id == tip.Id); if (_tips[keyword].Count == 0) - _tips.Remove(keyword, out var _); + _tips.Remove(keyword, out _); } foreach (string imagePath in tip.ImagePaths) @@ -314,7 +314,7 @@ public List GetTips(string keywords) var keywordList = keywords.Split(',') .Select(k => k.Trim()) - .Where(k => IsValidTipKeyword(k)) + .Where(IsValidTipKeyword) .ToList(); #if true From 1203a316a9924d25d62c72cf87714d9559e0bff6 Mon Sep 17 00:00:00 2001 From: Ed Halley <1223980+hariedo@users.noreply.github.com> Date: Thu, 1 May 2025 18:51:54 -0500 Subject: [PATCH 61/61] Update TipModule.cs --- DiscordBot/Modules/TipModule.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DiscordBot/Modules/TipModule.cs b/DiscordBot/Modules/TipModule.cs index 974c2ea1..0423737e 100644 --- a/DiscordBot/Modules/TipModule.cs +++ b/DiscordBot/Modules/TipModule.cs @@ -69,6 +69,7 @@ public async Task Tip(string keywords) var ids = string.Join(" ", tips.Select(t => t.Id.ToString()).ToArray()); await ReplyAsync($"-# Tip ID {ids}"); + await Context.Message.DeleteAsync(); } [Command("AddTip")] @@ -183,6 +184,7 @@ public async Task ListTips() [Summary("Shows available tip database commands.")] public async Task TipHelp() { + // NOTE: skips the RequireModerator commands, so nearly an empty list foreach (var message in CommandHandlingService.GetCommandListMessages("TipModule", true, true, false)) { await ReplyAsync(message);