From f1529cf9d30d189f6b24ff9be2ef0ef7fd819fea Mon Sep 17 00:00:00 2001 From: Thunder Date: Sat, 2 Sep 2023 18:16:31 -0400 Subject: [PATCH 1/4] Introduce channel "stickied messages" --- BLART/Bot.cs | 3 + BLART/Commands/StickiedMessages/AddMessage.cs | 36 ++++++ .../StickiedMessages/RemoveMessage.cs | 28 +++++ BLART/DatabaseType.cs | 2 + BLART/Modules/StickiedMessages.cs | 46 ++++++++ BLART/Objects/StickyMessage.cs | 22 ++++ BLART/Services/DatabaseHandler.cs | 111 ++++++++++++++++++ BLART/Services/EmbedBuilderService.cs | 6 + 8 files changed, 254 insertions(+) create mode 100644 BLART/Commands/StickiedMessages/AddMessage.cs create mode 100644 BLART/Commands/StickiedMessages/RemoveMessage.cs create mode 100644 BLART/Modules/StickiedMessages.cs create mode 100644 BLART/Objects/StickyMessage.cs diff --git a/BLART/Bot.cs b/BLART/Bot.cs index 07ddddc..9df0fa4 100755 --- a/BLART/Bot.cs +++ b/BLART/Bot.cs @@ -71,6 +71,9 @@ private async Task Init(string[] args) Log.Debug(nameof(Init), "Setting up raid protection.."); Client.UserJoined += RaidProtection.OnUserJoined; + Log.Debug(nameof(Init), "Setting up sticky messages.."); + Client.MessageReceived += StickiedMessages.OnMessageReceived; + Log.Debug(nameof(Init), "Installing slash commands.."); await SlashCommandHandler.InstallCommandsAsync(); Client.Ready += async () => diff --git a/BLART/Commands/StickiedMessages/AddMessage.cs b/BLART/Commands/StickiedMessages/AddMessage.cs new file mode 100644 index 0000000..0fcc300 --- /dev/null +++ b/BLART/Commands/StickiedMessages/AddMessage.cs @@ -0,0 +1,36 @@ +namespace BLART.Commands.StickiedMessages; + +using BLART.Services; +using Discord.Interactions; +using Discord.WebSocket; + +[Group("stick", "Commands to manage channel sticky messages.")] +public partial class StickiedMessages : InteractionModuleBase +{ + [SlashCommand("add", "Adds a sticky message to a channel.")] + public async Task Add([Summary("channel", "The channel to stick a message to.")]SocketTextChannel channel, [Summary("message", "The message to stick.")]string message) + { + if (!CommandHandler.CanRunStaffCmd(Context.User)) + { + await RespondAsync(embed: await ErrorHandlingService.GetErrorEmbed(ErrorCodes.PermissionDenied), ephemeral: true); + return; + } + + if (string.IsNullOrWhiteSpace(message)) + { + await RespondAsync("Sticky message cannot be empty!", ephemeral: true); + return; + } + + var sticky = DatabaseHandler.GetStickyMessage(channel.Id); + if (sticky != null) + { + await RespondAsync($"The {channel.Mention} channel already has an active sticky message! Remove it first.", ephemeral: true); + return; + } + + DatabaseHandler.AddEntry(channel.Id, message, DatabaseType.StickiedMessage, Context.User.Id); + await RespondAsync($"The following sticky message has been added to the {channel.Mention} channel.", ephemeral: true); + + } +} diff --git a/BLART/Commands/StickiedMessages/RemoveMessage.cs b/BLART/Commands/StickiedMessages/RemoveMessage.cs new file mode 100644 index 0000000..c160cf0 --- /dev/null +++ b/BLART/Commands/StickiedMessages/RemoveMessage.cs @@ -0,0 +1,28 @@ +namespace BLART.Commands.StickiedMessages; + +using BLART.Services; +using Discord; +using Discord.Interactions; + +public partial class StickiedMessages : InteractionModuleBase +{ + [SlashCommand("remove", "Removes a sticky message from a channel.")] + public async Task Remove([Summary("channel", "The channel to remove a stuck message from.")] ITextChannel channel) + { + if (!CommandHandler.CanRunStaffCmd(Context.User)) + { + await RespondAsync(embed: await ErrorHandlingService.GetErrorEmbed(ErrorCodes.PermissionDenied), ephemeral: true); + return; + } + + var sticky = DatabaseHandler.GetStickyMessage(channel.Id); + if (sticky == null) + { + await RespondAsync($"The {channel.Mention} channel does not have a sticky message.", ephemeral: true); + return; + } + + DatabaseHandler.RemoveEntry(channel.Id, DatabaseType.StickiedMessage); + await RespondAsync($"Sticky message has been removed from the {channel.Mention} channel!", ephemeral: true); + } +} diff --git a/BLART/DatabaseType.cs b/BLART/DatabaseType.cs index b9f0f3a..feaa5aa 100755 --- a/BLART/DatabaseType.cs +++ b/BLART/DatabaseType.cs @@ -9,4 +9,6 @@ public enum DatabaseType BugReport, SelfRole, Tags, + StickiedMessage, + StickiedMessageIDs, } \ No newline at end of file diff --git a/BLART/Modules/StickiedMessages.cs b/BLART/Modules/StickiedMessages.cs new file mode 100644 index 0000000..4ecb439 --- /dev/null +++ b/BLART/Modules/StickiedMessages.cs @@ -0,0 +1,46 @@ +using BLART.Objects; +using BLART.Services; +using Discord; +using Discord.WebSocket; +using System; + +namespace BLART.Modules; + +public class StickiedMessages +{ + public static async Task Post(StickyMessage message) + { + IGuild guild = Bot.Instance.Guild; + + IGuildUser staff = await guild.GetUserAsync(message.StaffId); + staff ??= await guild.GetCurrentUserAsync(); + + ITextChannel textChannel = await guild.GetTextChannelAsync(message.ChannelId); + if (textChannel != null) + { + IUserMessage m = await textChannel.SendMessageAsync(embed: await EmbedBuilderService.CreateStickyMessage(message.Message, staff)); + DatabaseHandler.AddEntry(m.Id, textChannel.Id.ToString(), DatabaseType.StickiedMessageIDs); + } + } + + public static async Task OnMessageReceived(SocketMessage message) + { + StickyMessage? msg = DatabaseHandler.GetStickyMessage(message.Channel.Id); + if (msg is null) + return; + + string? stickyId = DatabaseHandler.GetStickyMessageID(msg.ChannelId); + + if (stickyId is not null) + { + IMessage current = await message.Channel.GetMessageAsync(ulong.Parse(stickyId)); + if ((DateTime.UtcNow - current.Timestamp).TotalSeconds < 5) + return; + + await current.DeleteAsync(new() { AuditLogReason = "Creating new sticky message." }); + DatabaseHandler.RemoveEntry(current.Id, DatabaseType.StickiedMessageIDs); + } + + await Post(msg); + } +} \ No newline at end of file diff --git a/BLART/Objects/StickyMessage.cs b/BLART/Objects/StickyMessage.cs new file mode 100644 index 0000000..e71b3e5 --- /dev/null +++ b/BLART/Objects/StickyMessage.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BLART.Objects +{ + public class StickyMessage + { + public ulong StaffId { get; set; } + public ulong ChannelId { get; set; } + public string Message { get; set; } + + public StickyMessage(ulong channelId, string message, ulong staffId) + { + ChannelId = channelId; + Message = message; + StaffId = staffId; + } + } +} diff --git a/BLART/Services/DatabaseHandler.cs b/BLART/Services/DatabaseHandler.cs index 643db88..27a23d8 100755 --- a/BLART/Services/DatabaseHandler.cs +++ b/BLART/Services/DatabaseHandler.cs @@ -2,6 +2,7 @@ namespace BLART.Services; using System.Globalization; using System.Net; +using System.Threading.Channels; using BLART.Objects; using Discord; using Microsoft.Data.Sqlite; @@ -75,6 +76,22 @@ public static async Task Init(bool updateTables = false) "CREATE TABLE IF NOT EXISTS Tags(Id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, tag TEXT)"; cmd.ExecuteNonQuery(); } + + using (SqliteCommand cmd = conn.CreateCommand()) + { + Log.Info(nameof(Init), "Creating sticked messages table.."); + cmd.CommandText = + "CREATE TABLE IF NOT EXISTS StickiedMessages(Id INTEGER PRIMARY KEY AUTOINCREMENT, channelId TEXT, message TEXT, staffId TEXT)"; + cmd.ExecuteNonQuery(); + } + + using (SqliteCommand cmd = conn.CreateCommand()) + { + Log.Info(nameof(Init), "Creating sticked messages ID table.."); + cmd.CommandText = + "CREATE TABLE IF NOT EXISTS StickiedMessagesIDs(Id INTEGER PRIMARY KEY AUTOINCREMENT, messageId TEXT, channelId TEXT)"; + cmd.ExecuteNonQuery(); + } } await BugReporting.LoadDatabaseEntries(); @@ -96,6 +113,8 @@ public static void AddEntry(ulong id, string description, DatabaseType type, ulo DatabaseType.BugReport => "INSERT INTO BugReports(messageId, threadId) VALUES(@id, @string)", DatabaseType.SelfRole => "INSERT INTO SelfRoles(roleId) VALUES(@id)", DatabaseType.Tags => "INSERT INTO Tags(name, tag) VALUES(@name, @tag)", + DatabaseType.StickiedMessage => "INSERT INTO StickiedMessages(channelId, message, staffId) VALUES(@id, @string, @staff)", + DatabaseType.StickiedMessageIDs => "INSERT INTO StickiedMessagesIDs(messageId, channelId) VALUES(@id, @string)", _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; @@ -141,6 +160,8 @@ public static void RemoveEntry(int id, DatabaseType type) DatabaseType.BugReport => "DELETE FROM BugReports WHERE Id=@id", DatabaseType.SelfRole => "DELETE FROM SelfRoles WHERE Id=@id", DatabaseType.Tags => "DELETE FROM Tags WHERE Id=@id", + DatabaseType.StickiedMessage => "DELETE FROM StickiedMessages WHERE Id=@id", + DatabaseType.StickiedMessageIDs => "DELETE FROM StickiedMessagesIDs WHERE Id=@id", _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; @@ -166,6 +187,8 @@ public static void RemoveEntry(ulong userId, DatabaseType type) DatabaseType.Ban => "DELETE FROM Bans WHERE UserId=@id", DatabaseType.BugReport => "DELETE FROM BugReports WHERE messageId=@id OR threadId=@id", DatabaseType.SelfRole => "DELETE FROM SelfRoles WHERE roleId=@id", + DatabaseType.StickiedMessage => "DELETE FROM StickiedMessages WHERE channelId=@id", + DatabaseType.StickiedMessageIDs => "DELETE FROM StickiedMessagesIDs WHERE messageId=@id", _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) }; @@ -438,4 +461,92 @@ public static List GetTagNames() return tags; } + + public static StickyMessage? GetStickyMessage(ulong channelId) + { + StickyMessage? stick = null; + using (SqliteConnection conn = new(_connectionString)) + { + conn.Open(); + using (SqliteCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = "SELECT * FROM StickiedMessages WHERE channelId=@id"; + cmd.Parameters.AddWithValue("@id", channelId.ToString()); + + using (SqliteDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + string message = reader.GetString(2); + string staffId = reader.GetString(3); + stick = new StickyMessage(channelId, message, ulong.Parse(staffId)); + break; + } + } + } + + conn.Close(); + } + + return stick; + } + + public static List GetStickyMessages() + { + List result = new(); + + using (SqliteConnection conn = new(_connectionString)) + { + conn.Open(); + using (SqliteCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = "SELECT * FROM StickiedMessages"; + + using (SqliteDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + string channelId = reader.GetString(1); + string message = reader.GetString(2); + string staffId = reader.GetString(3); + result.Add(new StickyMessage(ulong.Parse(channelId), message, ulong.Parse(staffId))); + } + } + } + + conn.Close(); + } + + return result; + } + + public static string? GetStickyMessageID(ulong channelId) + { + string? result = null; + + ITextChannel channel = Bot.Instance.Guild.GetTextChannel(channelId); + if (channel is null) + return result; + + using (SqliteConnection conn = new(_connectionString)) + { + conn.Open(); + using (SqliteCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = "SELECT * FROM StickiedMessagesIDs WHERE channelId=@id"; + cmd.Parameters.AddWithValue("@id", channelId.ToString()); + + using (SqliteDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + result = reader.GetString(1); + break; + } + } + } + } + + return result; + } } \ No newline at end of file diff --git a/BLART/Services/EmbedBuilderService.cs b/BLART/Services/EmbedBuilderService.cs index 428a1a4..3a02fb6 100755 --- a/BLART/Services/EmbedBuilderService.cs +++ b/BLART/Services/EmbedBuilderService.cs @@ -12,4 +12,10 @@ public static async Task CreateBasicEmbed(string title, string descriptio Log.Info(nameof(CreateBasicEmbed), $"Sending embed {title}."); return await Task.Run(() => new EmbedBuilder().WithTitle(title).WithDescription(description).WithColor(color).WithCurrentTimestamp().WithFooter(Footer).Build()); } + + public static async Task CreateStickyMessage(string message, IGuildUser staff) + { + Log.Info(nameof(CreateBasicEmbed), $"Sending sticky embed {message}."); + return await Task.Run(() => new EmbedBuilder().WithTitle("Stickied Message").WithDescription(message).WithColor(Color.Blue).WithCurrentTimestamp().WithFooter(Footer).WithAuthor(staff).Build()); + } } \ No newline at end of file From fba85a3712e90945205a87d91259f9a9992565b9 Mon Sep 17 00:00:00 2001 From: Thunder Date: Sat, 2 Sep 2023 18:17:27 -0400 Subject: [PATCH 2/4] Unused --- BLART/Services/DatabaseHandler.cs | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/BLART/Services/DatabaseHandler.cs b/BLART/Services/DatabaseHandler.cs index 27a23d8..149e824 100755 --- a/BLART/Services/DatabaseHandler.cs +++ b/BLART/Services/DatabaseHandler.cs @@ -491,35 +491,6 @@ public static List GetTagNames() return stick; } - public static List GetStickyMessages() - { - List result = new(); - - using (SqliteConnection conn = new(_connectionString)) - { - conn.Open(); - using (SqliteCommand cmd = conn.CreateCommand()) - { - cmd.CommandText = "SELECT * FROM StickiedMessages"; - - using (SqliteDataReader reader = cmd.ExecuteReader()) - { - while (reader.Read()) - { - string channelId = reader.GetString(1); - string message = reader.GetString(2); - string staffId = reader.GetString(3); - result.Add(new StickyMessage(ulong.Parse(channelId), message, ulong.Parse(staffId))); - } - } - } - - conn.Close(); - } - - return result; - } - public static string? GetStickyMessageID(ulong channelId) { string? result = null; From db64f589bf4bd796ab2ee65f691e7ea5533632ba Mon Sep 17 00:00:00 2001 From: Thunder Date: Sat, 2 Sep 2023 18:19:37 -0400 Subject: [PATCH 3/4] Finish command and simplify --- BLART/Commands/StickiedMessages/AddMessage.cs | 2 +- BLART/Services/EmbedBuilderService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/BLART/Commands/StickiedMessages/AddMessage.cs b/BLART/Commands/StickiedMessages/AddMessage.cs index 0fcc300..31c06a2 100644 --- a/BLART/Commands/StickiedMessages/AddMessage.cs +++ b/BLART/Commands/StickiedMessages/AddMessage.cs @@ -30,7 +30,7 @@ public async Task Add([Summary("channel", "The channel to stick a message to.")] } DatabaseHandler.AddEntry(channel.Id, message, DatabaseType.StickiedMessage, Context.User.Id); - await RespondAsync($"The following sticky message has been added to the {channel.Mention} channel.", ephemeral: true); + await RespondAsync($"The following sticky message has been added to the {channel.Mention} channel.", embed: await EmbedBuilderService.CreateStickyMessage(message, Context.User), ephemeral: true); } } diff --git a/BLART/Services/EmbedBuilderService.cs b/BLART/Services/EmbedBuilderService.cs index 3a02fb6..03fab35 100755 --- a/BLART/Services/EmbedBuilderService.cs +++ b/BLART/Services/EmbedBuilderService.cs @@ -13,7 +13,7 @@ public static async Task CreateBasicEmbed(string title, string descriptio return await Task.Run(() => new EmbedBuilder().WithTitle(title).WithDescription(description).WithColor(color).WithCurrentTimestamp().WithFooter(Footer).Build()); } - public static async Task CreateStickyMessage(string message, IGuildUser staff) + public static async Task CreateStickyMessage(string message, IUser staff) { Log.Info(nameof(CreateBasicEmbed), $"Sending sticky embed {message}."); return await Task.Run(() => new EmbedBuilder().WithTitle("Stickied Message").WithDescription(message).WithColor(Color.Blue).WithCurrentTimestamp().WithFooter(Footer).WithAuthor(staff).Build()); From 33f474bcb89d47d5bc6c6f9f440c483d2e7dfe75 Mon Sep 17 00:00:00 2001 From: Thunder Date: Sat, 2 Sep 2023 18:26:28 -0400 Subject: [PATCH 4/4] Remove existing --- BLART/Commands/StickiedMessages/RemoveMessage.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/BLART/Commands/StickiedMessages/RemoveMessage.cs b/BLART/Commands/StickiedMessages/RemoveMessage.cs index c160cf0..d6fa84b 100644 --- a/BLART/Commands/StickiedMessages/RemoveMessage.cs +++ b/BLART/Commands/StickiedMessages/RemoveMessage.cs @@ -22,6 +22,18 @@ public async Task Remove([Summary("channel", "The channel to remove a stuck mess return; } + // Remove existing message + string? id = DatabaseHandler.GetStickyMessageID(channel.Id); + if (id is not null) + { + await DeferAsync(true); + + IMessage msg = await channel.GetMessageAsync(ulong.Parse(id)); + + if (msg is not null) + await msg.DeleteAsync(new() { AuditLogReason = "Removed message for deleted sticky message." }); + } + DatabaseHandler.RemoveEntry(channel.Id, DatabaseType.StickiedMessage); await RespondAsync($"Sticky message has been removed from the {channel.Mention} channel!", ephemeral: true); }